Utiliser les capteurs Yoctopuce avec Modbus TCP

Utiliser les capteurs Yoctopuce avec Modbus TCP

Régulièrement on nous demande si les YoctoHubs supportent le protocole Modbus TCP. La réponse est non, car le CPU des YoctoHubs est trop petit pour que l'on puisse ajouter le code du serveur Modbus TCP. La solution que nous recommandons est d'écrire un petit serveur Modbus TCP en Python à l'aide de la librairie pymodbus et d'utiliser notre librairie pour communiquer avec les modules Yoctopuce. C'est exactement ce que l'on a fait cette semaine.



Nous allons donc vous présenter un petit serveur Modbus TCP, qui publie les valeurs des capteurs Yoctopuce qui sont connectés sur les ports USB. Nous allons faire tourner ce petit serveur sur un Raspberry Pi, mais comme c'est du Python il devrait fonctionner sur n'importe quel OS, y compris Windows.

Pour configurer le mapping entre les modules Yoctopuce et les numéros de registre, ce serveur utilise un petit fichier de configuration device_mapping.txt. Chaque ligne correspond à un mapping, et un mapping est composé de trois champs : le numéro de registre, l'hardware ID du senseur Yoctopuce, et l'encodage de la valeur. Les encodages supportés sont int8, int16, int32, float 16 et float32.

Voici par exemple un fichier de configuration pour trois senseurs Yoctopuce:

0x0000,METEOMK2-114F07.temperature,float32 0x0002,METEOMK2-114F07.humidity,int32 0x0004,YPROXIM1-81237.proximity1,int32



L’installation


Pour installer ce petit serveur Modbus TCP, il faut cloner le code depuis GitHub:

git clone https://github.com/yoctopuce-examples/ymodbustcp.git cd ymodbustcp



Et installer à l'aide de pip les librairies utilisées par le serveur, à savoir pymodbus et yoctopuce.

pip install pymodbus pip install yoctopuce



Il faut ensuite éditer le fichier device_mapping.txt pour qu'il corresponde aux modules Yoctopuce présents sur la machine.

Dans notre cas, nous voulons publier la température et l'humidité du Yocto-Meteo-V2 METEOMK2-114F07 ainsi que la luminosité du Yocto-Light-V3 LIGHTMK3-C0905 :

0x0000,METEOMK2-114F07.temperature,float32 0x0002,METEOMK2-114F07.humidity,int32 0x0004,LIGHTMK3-C0905.lightSensor,int32



Il ne reste plus qu'à lancer le serveur :

./ymodbustcp.py



Et voilà, nos modules Yoctopuce sont utilisables dans une infrastructure Modbus TCP. Par exemple, la valeur de nos senseurs peut être lue à l'aide de l'application Simply Modbus TCP Client

La valeur de nos senseurs peut être lue à l'aide de l'application Simply Modbus TCP
La valeur de nos senseurs peut être lue à l'aide de l'application Simply Modbus TCP



L'implémentation


Le code source de ce serveur Modbus TCP est disponible sur Github :

https://github.com/yoctopuce-examples/ymodbustcp

Le code est basé sur l'exemple "Callback Server" de la librairie pymodbus. Cette librairie permet d'écrire facilement un client ou un serveur Modbus TCP, c'est du reste pour cette raison que nous avons décidé d'utiliser Python pour écrire ce petit serveur.

Pour mettre à jour les registres Modus du serveur, il faut simplement créer une classe qui hérite de ModbusSparseDataBlock et qui implémente la méthode setValues.

class YocotpuceBinding(object):
  def __init__(self, reg_no, hwid, encoding):
    self.reg_addr = reg_no
    self.hwid = hwid
    self.ysensor = YSensor.FindSensor(hwid)
    self.encoding = encoding
    self.reg_len = 2
    if self.encoding == 'int8':
        self.reg_len = 1
    elif self.encoding == 'int32' or self.encoding == 'float32':
        self.reg_len = 2

  def encode_value(self, val):
    builder = BinaryPayloadBuilder(byteorder=Endian.Big)
    if self.encoding == 'int8':
        builder.add_8bit_int(int(val))
    elif self.encoding == 'int16':
        builder.add_16bit_int(int(val))
    elif self.encoding == 'int32':
        builder.add_32bit_int(int(val))
    elif self.encoding == 'float16':
        builder.add_16bit_float(val)
    elif self.encoding == 'float32':
        builder.add_32bit_float(val)
    ba = builder.to_registers()
    return ba

  def update_measure(self, org_val, address, count):
    end_addr = address + count
    # skip device that are outside the range
    if end_addr <= self.reg_addr:
        return
    if address > (self.reg_addr + self.reg_len):
        return
    # get sensor value
    val = self.ysensor.get_currentValue()
    full_register = self.encode_value(val)
    # and update the corresponding register
    offset = self.reg_addr
    for word in full_register:
        org_val[offset] = word
        offset += 1

  def get_hwid(self):
    return self.hwid

  def get_reglen(self):
    return self.reg_len


class YoctopuceDataBlock(ModbusSequentialDataBlock):
  def __init__(self, devices):
    self.devices = devices
    start = 0xffff
    end = 0
    for reg in devices.keys():
        reglen = devices[reg].get_reglen()
        if reg < start:
            start = reg
        if reg + reglen > end:
            end = reg + reglen
    values = [0] * (end - start)
    super(YoctopuceDataBlock, self).__init__(start, values)

  def getValues(self, address, count=1):
    for reg in self.devices.keys():
        self.devices[reg].update_measure(self.values, address, count)
    values = super(YoctopuceDataBlock, self).getValues(address, count)
    return values



Conclusion


Ce serveur n'est pas une solution à utiliser telle quelle en production, mais il devrait vous permettre de réaliser vos tests et autres projets internes. Nous avons gardé le code le plus simple possible afin que vous puissiez facilement adapter ce serveur à vos besoins.

En conclusion, même si les YoctoHubs ne supportent pas nativement Modbus TCP, il est possible de contourner cette limitation à l'aide d'un Raspberry Pi et de ce serveur.

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.