 _______ ______  _____  _____
 |  |  | |_____]   |   |     |
 |  |  | |_____] __|__ |_____|

  _____   ______  _____  _______ _______ _______ _______  _____   ______
 |_____] |_____/ |     | |       |______ |______ |______ |     | |_____/
 |       |    \_ |_____| |_____  |______ ______| ______| |_____| |    \_



Installation du processeur Digimat MBIO 
=======================================

Le processeur Digimat MBIO est activé depuis le fichier digimat.conf de la CPU

    mbioprocessor

Par défaut, le processeur MBIO utilise l'interface eth0 pour ses communications. Etant donné que le
processeur MBIO doit se connecter a la CPU, il est important que son IP ne corresponde pas à l'IP
d'une CPU. Dès lors, l'usage voudra que l'on attribue une carte lan virtuelle (eth0:n) au processeur
MBIO. 

    # Virtual eth0:3 mbio interface 
    eth0:3 = 192.168.139.101 
    mbioprocessor = 192.168.139.101

L'interface réseau utilisée par le processeur MBIO peut être spécifiée par les alias suivants

    eth0|cpu   adresse ip du port lan physique eth0
    eth0:1..n  adresse ip du port lan virtuel eth0:n 

dès lors, la configuration suivante pourrait être "générique"

    mbioprocessor = eth0:3

Par convention, on utilisera l'interface eth0:3 pour le processeur MBIO, ainsi que l'IP
192.168.139.100+N (N=CPU number) dans un plan d'adressage Digimat standard. Il convient ensuite de
définir l'id MBIO côté CPU pour les connexions avec le processeurs MBIO. L'id côté CPU doit
correspondre à l'id côté processeur (pseudo sécurité). Par convention on utilisera l'id 6000+N
(N=CPU number). La clé secrète permet d'authentifier la connexion (session) côté CPU. Seules les
connexions authentifiées sont autorisées à échanger des données MBIO (synchronisation des variables,
par exemple). Cette clé doit être également connue par le processeur MBIO. Le processus
d'authentification utilise un mécanisme de challenge pour l'authentification, de sorte que la clé
secrète n'est jamais directement échangée entre les participants.

    mbio = 6001, MySecretKey, 1024

Le 3ème paramètre de l'option "mbio" est le nombre de points (ressources) mbio à créer dans la CPU
(par défaut 1024). Lorsque le processeur MBIO est activé, les services MBIO seront automatiquement
installés par la CPU. Ceci peut néanmoins être réalisé manuellement

    pythoninstaller RAZ 
    pythoninstaller mbio

La commande RAZ est optionnelle, mais reste utile pour provoquer la desinstallation complète de
l'environement Python existant. Cette commande va installer l'environnement Python (précompilé et
rendu disponible sur www.digimat.ch) ainsi que toutes les dépendances (modules) nécessaires (dépots
PyPi). Le processeur MBIO est ensuite automatiquement lancé par inittab/mbio.launch. On peut
vérifier que le service est bien lancé avec un simple "ps"

    1140 root      0:00 /usr/local/bin/python /usr/local/bin/mbioprocessor.py

La commande "mbio" offre une "toolbox" permettant de manipuler facilement les différents
outils/scripts de l'environnement MBIO (mbio --help) :

    MBIO toolbox

    --restart       restart the mbio processor (systemctl restart mbio)
    --update        update the mbio config file, restart if required (mbioupdate)
    --upgrade       update the mbio config file + mbio processor (digimat.mbio),
                    restart if required (mbioupdate --upgrade)
    --lock          halt and lock the mbio processor service (mbio.lock)
    --unlock        unlock the mbio processor service (mbio.unlock)
    --interactive   lock the mbio processor service, and start an interactive 
                    mbio session (mbio.interactivelaunch)
    -i              idem --interactive
    --install       install the mbio processor (pythoninstaller mbio)
    --config        affiche le fichier de configuration mbio
    --log           launch the debug logserver (python -m digimat.logserver)
    --pid           affiche le numéro de processus du processeur MBIO
    --pack          crée un package Python (digimat.mbio) pour installation manuelle
    --version       affiche la version du package Python digimat.mbio installée


Fichier de configuration du processeur MBIO
===========================================

Le fichier de configuration (config.xml) est au format XML, stocké dans le répertoire du processeur
ou dans /etc/sysconfig/digimat/mbio dans le cas d'une CPU4. La configuration des ressources MBIO
gérées par le processeur MBIO est donc faite dans un fichier XML. Au premier abord cela peut
paraître un peu "barbare" mais cela s'avère au contraire très pratique pour gérer "en masse" des
configurations répétées, ce qui est tout à fait adapté aux ressources MBIO (système
d'entrées/sorties déportées).

Le fichier de configuration du processeur MBIO est entièrement contenu dans une balise "config".
L'attribut "interface" permet d'associer le socket du processeur à une interface réseau "source"
particulière. Le fichier de configuration XMl n'est pas sensible à la casse.

    <Config interface='192.168.139.101'>
        ...
    </Config>


Attention : l'interface est en principe configurée directement depuis le fichier de configuration
digimat.conf et ne devrait pas être redéfinie dans le fichier de configuration mbio.

Le processeur MBIO intègre un mécanisme de "scanner réseau". Il est donc possible de définir
l'adressage du réseau TCP/IP utilisé avec l'attribut 'network', ainsi que le gateway par défaut (gw)
a utiliser en cas d'adressage IP automatisé

    <Config interface='192.168.139.101' network='192.168.139.0/24' gw='192.168.0.254'>
        ...
    </Config>

Il est possible de mentionner un nom de zone "générale" dans la config avec l'attribut "zone". Les
gateways/devices utiliseront par défaut ce nom de zone (override possible au sein des objets
gateway et device). 

Les variables MBIO seront synchronisées avec le(s) notifier(s) déclaré(s) (normalement un seul
notifier, une CPU Digimat-4). Un notifier est déclaré par la balise "target". L'attribut "name"
permet de nommer le notifiers (logs) et les paramètres de connexions sont définis par les attributs
"host", "port (5000)", "id" et "passkey". L'id (0-65535) doit correspondre à l'id défini côté CPU (mini
securité permettant d'éviter les mauvaises configurations). Id conseillé = 6000 + numéro de CPU. La
clé de sécurité (idem config CPU) doit être renseignée par l'attribut passkey. 

    <Notifiers>
        <Target name='CPU' host='192.168.0.177' port='5000' id='6000' passkey='MySecretKey' />
    </Notifiers>

En general, le host du notifier pointe vers l'adresse IP de la CPU, donc "eth0". Le processeur MBIO
est capable de retrouver automatiquement les ip correspondantes aux alias suivants

    eth0|cpu   adresse ip du port physique eth0
    eth0:1..n  adresse ip du port virtuel eth0:n 

Dès lors,  il est possible de généraliser la déclaration d'un notifier "CPU" ainsi

    <Notifiers>
        <Target name='station' host='eth0' port='5000' id='...' passkey='...' />
    </Notifiers>

Pour des questions d'optimisation de la liaison réseau, il est possible de limiter la
synchronisation réseau de certaines variables uniquement entre le processeur MBIO et les notifiers,
en définissant un filtre défini de plusieurs règles "enable" et "disable". Le filtre est appliqué
sur l'ensemble des notifiers. Il est composé d'une suite de règles, traitées dans l'ordre de
déclaration. Par défaut, il n'y a pas de filtre configuré (=enable all). Une règle est définie par
une balise "enable" ou "disable" ainsi qu'un attribut "key" définissant sur quels noms de variables
il s'applique. Il est possible d'utiliser un "*" (*, nom*, *nom, *nom*) pour cibler des variables en
particulier. Pour rappel, une variable MBIO est de la forme gatewayName_deviceAddress_valueName,
comme par exemple "gw1_4_do1"). Le gateway représente l'interface ModBus/TCP distante, le device
représente le module ModBusRTU associé au gateway donné et la value représente la variable MBIO du
device donné. Comme une value dispose d'un état enable=True par défaut, il faut commencer par
désactiver tout ou partie des values avant de réactiver les values souhaitées.

    <Notifiers>
        <Filter>
            <Disable key='*'/>
            <Enable key='gw1*'/>
        </Filter>
    </Notifiers>

A noter qu'il est possible de demander au processeur MBIO de déclarer automatiquement dans un
notifier (une CPU) certaines variables (un item représente une variable MBIO dans la CPU). La
configuration doit fournir le numéro du premier "item" utilisable pour l'autodéclaration, (par
défaut 0). Ce numéro d'item est ensuite automatiquement incrémenté.

    <Notifiers>
        <Target name='CPU' host='192.168.0.177' port='5000' id='6000'>
            <Declare item='100' autoskip='5' autoalign='10'>
                <Values key='*' />
            </Declare>
        </Target>
    </Notifiers>

L'autodéclaration n'a lieu que pour les variables qui ne sont pas déjà "mappées" sur un item de la
CPU. Lorsqu'une nouvelle variable doit être mappée sur un item, la CPU utilise un algorithme qui
essaie de trouver un item non installé après le premier item qui contient une variable "semblable".
Dès lors, il est intéressant de laisser quelques items libres après un "groupe d'item" (variable
dont le nom a un préfixe commun). L'attribut "autoskip" permet de définir le nombre de "places" a
laisser libre entre 2 groupes de variables (par défaut 0). L'attribut "autoalign" permet de
spécifier, une fois le autoskip traité, d'ajouter autant de skip supplémentaire que nécessaire pour
que la position du prochain item soit divisable par N (N>1).

Plusieurs balises "declare" peuvent être utilisées. Si le numéro d'item n'est pas précisé, la
numérotation du dernier item utilisé est automatiquement reprise. Il est possible de déclarer
plusieurs balises "values" dans une balise "declare". La syntaxe de sélection des values est la même
que celle utilisée pour les filtres.

L'étape suivante consiste a déclarer les gateways (un gateway est une interface ModBusTCP, contenant
un ou plusieurs devices ModBusRTU). Un gateway est défini par attribut name (gw1, bureau120) et un
host (adresse ip). Le port de communication peut être modifié avec l'attribut "port", mais il est
réglé à 502 par défaut (=ModBusTCP).

    <Gateway name='gw1' host='192.168.0.210' port='502'>
        <Device ... />
        <Device ... />
        <Device ... />
    </Gateway>

Attention, le nom d'une variable MBIO (value) est déterminé par le nom du gateway, l'adresse du
device et le nom de la value, les champs étant séparés par des "_". Côté CPU, ces IDs sont limités à
32 caractères. Compte tenu que le véritable nom de variable est celui de la value, il faut limiter
au maximum le nom d'un gateway ou d'un device. Les caractères spéciaux (en particulier le "_" ne
sont pas autorisés pour nommer ces champs.

Pour chaque gateway, il faut ensuite déclarer les devices à gérer. Un device est défini par une
adresse ModBusRTU "address" (1-254), un nom de fournisseur "vendor", ainsi qu'un modèle "model". 

    <Gateway>
        <Device vendor='MetzConnect' model='DO4' address='4'>
            ...
        </Device>
    </Gateway>

Seuls les devices supportés par le processeur MBIO peuvent être déclarés. Un nouveau type de device
devra donc être préalablement intégré dans le processeur MBIO avant de pouvoir être utilisé. La
version 0.1.15 supporte les devices suivants

    Vendor         Model         Description
    ------------   ------------  ---------------------------------------------------
    MetzConnect    DI4           4 Digital Inputs
    MetzConnect    DI10          10 Digital Inputs
    MetzConnect    DO4           4 Digital Outputs
    MetzConnect    AI8           8 Analog Inputs
    MetzConnect    AO4,AO4P      4 Analog Outputs
    Belimo         P22RTH        Sonde configurable Modbus avec/sans sonde CO2
    Belimo         Actuator      Servo-moteur de vanne/clappet
    Sensortec      EL-D          Sonde configurable Modbus avec/sans sonde CO2+VOC 
    Digimat        SIO           Multi I/O Digimat board (IP Smart IO)
    EBM            Base          Moteur EBM-Pabst
    ZiehlAbbeg     Base          Moteur Zhiel-Abbeg (à venir)
    Generic        N/A           Lecture/écriture libre de variables ModBus (alpha)

Le processeur MBIO gère l'établissement et le maintien de la connexion ModBusTCP vers chaque
gateway. Lorsque la connexion vers un gateway est active, le traitement des devices associés est
activé. La gestion d'un device commence par l'état OFFLINE. Du mode OFFLINE, le device passe
automatiquement au mode PROBE qui tente de lire une ou plusieurs variable(s) ModbusRTU de
référence(s) pour vérifier si le device est bien actif et si possible celui que l'on attend. Si tel
est le cas, le mode POWERON est activé. En général, toute erreur de communication activera le mode
ERROR, qui retournera après un certain temps au mode OFFLINE. Dans le mode POWERON, le processeur
MBIO initialise le device pour que son mode de fonctionnement corresponde à sa configuration (par
exemple : configuration du type d'entrées analogiques). Une fois que la phase de configuration est
terminée, le device passe en mode ONLINE qui consiste à rafraichir périodiquement l'état des
variables MBIO associées avec l'état physique du device (refresh). S'il y a des variables à écrire
-- c'est à dire à envoyer au device (sync) -- c'est également lorsque le mode ONLINE est actif que
cela est pris en compte. Lorsqu'un device doit s'arrêter, si la communication est active, le mode
POWEROFF est activé. C'est un mode comparable au mode POWERON (sans garantie de pouvoir être
éxécuté) qui permet de mettre en arrêt un device (lors d'un reset par exemple). Par exemple, pour
une sonde configurable Belimo, les curseurs HMI (setPoints) sont désactivés. Si un halt "permanent"
n'a pas été demandé (mode HALT), le device retourne ensuite automatiquement au mode OFFLINE.

Un gateway, tout comme un device, peut être désactivé simplement depuis la configuration par
l'attribut "enable" sans devoir complètement l'éliminer de la configuration. A noter que toutes les
variables dépendantes ne seront alors simplement pas déclarées.

    <Gateway name='gw1' host='192.168.0.210' enable='false'>
    <Device vendor='MetzConnect' model='DO4' address='4' enable='false'>

A noter que le processeur MBIO peut prendre en charge la découverte automatique et la configuration
des gateways, par exemple via Telnet pour les GW MetzConnect. Si l'on veut pouvoir profiter de ces
fonctionalités, il faut définir le modèle et l'adresse MAC des Gateways dans le fichier de
configuration

    <Gateway name='gw1' host='192.168.0.233' 
        model='metzconnect' mac='70:b3:d5:a5:8b:b5' password='digimat' >
      ...
    </Gateway>

Dans l'exemple ci-dessus, le processeur MBIO peut effectuer, via mbio.netscan('192.168.0.0/24'), une
recherche des gateways disponibles sur le réseau et, par l'adresse MAC, faire le joint avec la
configuration XML des Gateways. Si l'adresse IP d'un gateway devait ne pas correspondre à l'IP
configurée, une tentative de reconfiguration automatique est lancée. A noter que le password par
défaut peut être changé (attribut password) lors du processus de reconfiguration automatique. Cela
tend à "protéger" contre une reconfiguration auto les Gateways "déjà configurés". A noter que ce
mécanisme s'adapte au système de configuration offert par le gateway. Il faut donc renseigner le
"model" du gateway (MetzConnect, Digimat, ...), en plus de l'adresse MAC.

L'attribut 'zone' permet de définir le libellé de la zone auquel le gateways est rattaché (le nom du
bureau, par exemple). Cet attribut sera automatiquement propagé aux éléments contenus dans le
gateway (MBIODevice, MBIOValue) pour autant qu'il ne soit pas redéfini "plus bas". L'attribut 'zone'
est également présent pour la définition des devices.

Tous les changements d'état des variables seront automatiquement transmis aux notifiers pour autant
que

    -- la connexion au notifier soit active
    -- la variable ne soit pas déclarée comme disabled (enable=False)
    -- les filtres des notifiers n'excluent la variable
    -- le changement d'état provoque un déclenchement de la notification
       (unité ON/OFF -> changement d'état, unité analogique --> dV>=resolution) 
       ou que l'unité de la variable a changé,
       ou que les flags d'état de la variable ont changé (ERROR, OVERRIDE, ...)

Lors de l'établissement d'une connexion entre le processeur MBIO et un notifier (CPU), l'état de
l'ensemble des variables du processeur (filtres pris en compte) est transmis au(x) notifier(s)
(resynchronisation). Une fois le lien établi, l'état des variables est transmis a) sur changement
d'état ou b) après une période de non activité (par exemple 30s). Côté notifier (CPU), lorsqu'une
variable n'a pas été réceptionnée après un certain temps (par exemple 30s), un message de demande de
synchronisation est envoyée au processeur (pour chaque variable non rafraichie). La non réception
d'un rafraichissement d'une variable (typiquement après 60s) est donc considéré comme une erreur.
Pour les valeurs envoyées depuis la CPU au notifier (WRITE), un REWRITE de la valeur est
automatiquement envoyé toutes les 30s tant que l'état de la valeur (retour d'état) ne correspond pas
au "toReachValue" (pour s'assurer que la valeur finale parviennent bien à destination -- en réécrivant
périodiquement la consigne tant que l'état n'est pas satisfait) 

Le processus de synchronisation des variables peut donc générer un trafic réseau "intense". Il est
donc important de se poser la question du cheminement réseau des données échangées. En particulier,
il faut se demander s'il n'est pas possible de raccorder un processeur MBIO sur un port Ethernet
dédié de la CPU (de manière à séparer le trafic MBIO du reste du réseau LAN). A noter qu'un
mécanisme automatique désactive la transmission des notifications d'une variable (MBIO->CPU) si
cette variable n'est pas "mappée" côté CPU.

Le processeur MBIO peut effectuer un scan au démarrage (puis optionnellement toutes les 'refresh'
secondes). L'activation du scanner est configuré avec la balise "scanner"

    <Scanner refresh='3600' threads='64'>
        ...
    </Scanner>

Par défaut le scan n'est effectué qu'une seule fois, 15 secondes après le démarrage du processeur.
Si l'attribut "refresh" est configuré, alors le scan sera automatiquement relancé toutes les N
secondes. Le scan réseau est effectué par un pool de 32 threads, configurable avec l'attribut
'threads'. La configuration du réseau à scanner est reprise de la balise générale 'Config', mais il
est possible de spécifier le réseau à scanner avec l'attribut 'network'

    <Scanner network='172.16.2.0/24'>
        ...
    </Scanner>

Il est nécessaire de configurer les services de scan à activer dans le processur de scan. Les
services suivants sont actuellement supportés

    SIO     Scanner pour modules Digimat SmartIO (SIO)
    MC      Scanner pour gateways ModbusTCP MetzConnect

La configuration des service de scan est effectuée de la manière suivante 

    <Scanner refresh='3600'>
        <SIO/>
        <MC/>
    </Scanner>

A noter que les services de scan peuvent êtres eux même configurés avec des attributs. Par exemple,
le service SIO accepte un attribut 'token' qui peut être fourni pour l'authentification avec l'API
de configuration (par défaut, le processeur MBIO connait le token de configuration d'usine).


A. Devices MetzConnect
======================


A.1. Device DO4
---------------

    <Device vendor='MetzConnect' model='DO4' address='4'/>

Il est possible de définir avec l'attribut "watchdog" un délai (en secondes) après lequel le device
appliquera les états par défaut en cas de perte de communication.

    <Device vendor='MetzConnect' model='DO4' address='4' watchdog='60' />

Ce device offre un accès aux 4 sorties digitales DO0 à DO3

    MBIODeviceMetzConnectMRDO4(gw1_mb4=METZ CONNECT GmbH/MR-DO4, ONLINE)
    ├── MBIOValueDigital(gw1_mb4_comerr=False)
    ├── MBIOValueDigital(gw1_mb4_override=False, 0s)
    ├── MBIOValueDigitalWritable(gw1_mb4_do0=False, 0s)
    ├── MBIOValueDigitalWritable(gw1_mb4_do1=True, 0s)
    ├── MBIOValueDigitalWritable(gw1_mb4_do2=False, 0s)
    └── MBIOValueDigitalWritable(gw1_mb4_do3=True, 0s)

Il est possible de configurer séparément chaque sortie DO. Les canaux non mentionnés sont activés
par défaut, configurés avec une configuration de base.

    <Device vendor='MetzConnect' model='DO4' address='4'>
        <DO0 enable='false'/>
        <DO1 invert='true' default='true'/>
        <DO3 default='false'/>
    </Device>

L'attribut "enable" permet de désactiver (désinstaller) une sortie. Cette sortie ne générera plus de
trafic réseau et la synchronisation (sync) des données peut être désactivée (limitation du trafic
ModBusRTU). L'attribut "invert" permet d'inverser la polarité de la sortie (un état EN provoquera la
mise du relai en position OFF). L'attribut "default" permet la définition de la valeur par défaut
qui sera appliquée sur le relai en cas de perte de communication (voir attribut "watchdog" sur le
device). Attention, si le watchdog est déclaré (>0), *toutes* les sorties DO prendons les états par
défaut. Un état par défaut non défini est compris comme "OFF". A noter que les valeurs BOOL, dans
tout le fichier de config, peuvent être écrites de différentes manières équivalentes

        False <--> 0, Off, No (casse non prise en compte)
        True  <--> 1, On, Yes (casse non prise en compte)

Ce device déclare les variables "systèmes" suivantes

    -- gw1_4_comerr : TRUE s'il y a un erreur ide communication avec ce device
    -- gw1_4_override : TRUE s'il y a au moins une sortie en MANUEL (physiquement) sur ce device

A noter que si le device est en erreur (par exemple pas de communication), alors toutes les
variables voient leur flag d'état ERROR activés. Les sorties qui sont en MANUEL (physiquement)
voient leur flag d'état OVERRIDE activés.


A.2. Device DI10
----------------

    <Device vendor='MetzConnect' model='DI10' address='3'/>

Ce device offre un accès aux 10 sorties digitales DO0 à DO9

    MBIODeviceMetzConnectMRDI10(gw1_mb3=METZ CONNECT GmbH/MR-DI10, ONLINE)
    ├── MBIOValueDigital(gw1_mb3_comerr=False)
    ├── MBIOValueDigital(gw1_mb3_di0=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di1=True, 0s)
    ├── MBIOValueDigital(gw1_mb3_di2=True, 0s)
    ├── MBIOValueDigital(gw1_mb3_di3=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di4=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di5=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di6=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di7=False, 0s)
    ├── MBIOValueDigital(gw1_mb3_di8=False, 0s)
    └── MBIOValueDigital(gw1_mb3_di9=False, 0s)

Il est possible de configurer séparément chaque entrée. Les canaux non mentionnés sont activés par
défaut, configurés avec une configuration de base.

    <Device vendor='MetzConnect' model='DI10' address='3'>
        <DI0 enable='false'/>
        <DI1 invert='true'/>
    </Device>

L'attribut "enable" permet de désactiver (désinstaller) une entrée. Cette entrée ne générera plus de
trafic réseau. L'attribut "invert" permet d'inverser la polarité de l'entrée. 

Ce device déclare les variables "systèmes" suivantes

    -- gw1_3_comerr : TRUE s'il y a un erreur de communication avec ce device

A noter que si le device est en erreur (par exemple pas de communication), alors toutes les
variables voient leur flag d'état ERROR activés.


A.3. Device DI4
----------------

    <Device vendor='MetzConnect' model='DI4' address='3'/>

Idem device DO10 mais avec seulement 4 canaux.


A.4. Device AO4
----------------

    <Device vendor='MetzConnect' model='AO4' address='2'/>

Il est possible de définir avec l'attribut "watchdog" un délai (en secondes) après lequel le device
appliquera les états par défaut en cas de perte de communication.

    <Device vendor='MetzConnect' model='AO4' address='2' watchdog='60' />

Ce device offre un accès aux 4 sorties analogiques AO0 à AO3

    MBIODeviceMetzConnectMRAOP4(gw1_mb2=METZ CONNECT GmbH/MR-AOP4, ONLINE)
    ├── MBIOValueDigital(gw1_mb2_comerr=False)
    ├── MBIOValueDigital(gw1_mb2_override=False, 0s)
    ├── MBIOValueWritable(gw1_mb2_ao0=73.9%, 0s)
    ├── MBIOValueWritable(gw1_mb2_ao1=67.9%, flags=[X], 0s)
    ├── MBIOValueWritable(gw1_mb2_ao2=73.9%, 0s)
    └── MBIOValueWritable(gw1_mb2_ao3=78.9%, 0s)

Il est possible de configurer séparément chaque sortie AO. Les canaux non mentionnés sont activés
par défaut, configurés avec une configuration de base. L'unité implicite d'un canal AO est le "%"
(valeurs 0..100).

    <Device vendor='MetzConnect' model='AO4' address='2'>
        <AO0 lrange='50' hrange='80' default='100' />
        <AO1 min='10' max='70' resolution='5' />
        <AO2 enable='false' />
    </Device>

L'attribut "enable" permet de désactiver (désinstaller) une sortie. Cette sortie ne générera plus de
trafic réseau et la synchronisation (sync) des données peut être désactivée (limitation du trafic
ModBusRTU). L'attribut "default" permet la définition de la valeur par défaut qui sera appliquée sur
le relai en cas de perte de communication (voir attribut "watchdog" sur le device). Attention, si le
watchdog est déclaré (>0), *toutes* les sorties AO prendons les états par défaut. Un état par défaut
non défini est compris comme "0". Les attributs "lrange" (default 0) et "hrange" (default 100)
permettent de déclarer les zones mortes (signal utilisable effectif 0%=lrange, 100%=hrange). Le
pilotage d'une sortie 2 à 10V sera donc configurée avec l'attribut lrange=20. Les attributs "min"
(defaut 0) et "max" (defaut 100) permettent de définir les limites basses/hautes de la valeur
autorisée (après application des zones mortes). L'attribut résolution permet de déterminer la
résolution analogique déclenchant les notifications (changement d'état), par défaut 1%.

L'attribut "invert" permet d'inverser le sens d'action (0%=10V, 100%=0V).

Ce device déclare les variables "systèmes" suivantes

    -- gw1_2_comerr : TRUE s'il y a un erreur de communication avec ce device
    -- gw1_2_override : TRUE s'il y a au moins une sortie en MANUEL (physiquement) sur ce device

A noter que si le device est en erreur (par exemple pas de communication), alors toutes les
variables voient leur flag d'état ERROR activés. Les sorties qui sont en MANUEL (physiquement)
voient leur flag d'état OVERRIDE activés.


A.5. Device AI8
----------------

    <Device vendor='MetzConnect' model='AI8' address='1'/>

Ce device offre un accès aux 4 entrées analogiques universelles AI0 à AI7

    MBIODeviceMetzConnectMRAI8(gw1_mb1=METZ CONNECT GmbH/MR-AI8, ONLINE)
    ├── MBIOValue(gw1_mb1_ai0=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai1=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai2=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai3=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai4=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai5=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai6=0C, flags=[E], 0s)
    ├── MBIOValue(gw1_mb1_ai7=0C, flags=[E], 0s)
    └── MBIOValueDigital(gw1_mb1_comerr=False)

Il est possible de configurer séparément chaque entrée AI. Les canaux non mentionnés sont activés
par défaut, configurés avec une configuration de base. L'unité implicite d'un canal AI est le "C".

    <Device vendor='MetzConnect' model='AI8' address='1'>
        <AI0 type='pt1000' resolution='0.1' />
        <AI1 offset='-0.5' />
    </Device>

L'attribut "enable" permet de désactiver (désinstaller) une entrée. Cette entrée ne générera plus de
trafic réseau. L'attribut "type" permet de définir le type de l'entrée (physique) : 

    -- unité "C" implicite pour les types : pt100, pt500, pt1000, 
       ni1000-tk5000, ni1000-tk6180, 
       balco500, 
       kty81-110, kty81-210, 
       ntc-1k8, ntc-5k, ntc-10k, ntc-20k, ntc-10k-carel,
       lm235
    -- unité "ohm" implicite pour le types : ohm
    -- unité "V" implicite pour le type : 10v, 0-10v, 2-10v
    -- unité "%" implicite pour le type : 100%, 0-100%, 20-100%
    -- unité "pot" (à venir)

Pour les types "ohm" ou "10v", l'attribut complémentaire "unit" permet de (re)définir l'unité de la
valeur mesurée (string ou numéro). Les attributs "y0" (defaut 0) et "y1" (defaut 10) permettent de
définir une courbe de compensation vmin->y0, vmax->y1. Une sonde -50C..150C sur un signal 0-10V sera
donc configurée ainsi

    <AI1 type='10v' y0='-50' y1='150' unit='C'/>

Les attributs "x0" et "x1" permettent de spécifier la gamme utile du signal d'entrée (par défaut
x0=0 et x1=10). Si le type est '2-10V', (x0, y1) est implicitement configuré comme (2, 10). Si le 
type est '20-100%', (x0, y1) est implicitement configuré comme (20, 100).

L'attribut résolution permet de déterminer la résolution analogique déclenchant les notifications
(changement d'état), par défaut 0.1C. L'attribut "offset" permet de déclarer un offset (positif ou
négatif) qui sera ajouté systématiquement sur la valeur finale.

Ce device déclare les variables "systèmes" suivantes

    -- gw1_1_comerr : TRUE s'il y a un erreur sur ce device

A noter que si le device est en erreur (par exemple pas de communication), alors toutes les
variables voient leur flag d'état ERROR activés.


Divers
------

A noter que l'on peut activer, après la déclaration des devices MetzConnect, une recherche
automatisée des devices connectés. Cela est pratique en mode "debug" puisque cela déclare alors
automatiquement les devices détectés, avec une configuration par défaut.

    <Discover start='1' end='32' maxerrors='3' />

Cela provoque une recherche des devices éventuellement présents aux adresses 1 à 32. La recherche
est stoppée après 3 tentatives de lecture infructueuses (il faut donc que les devices soient
adressés "sans trous").


B. Devices Digimat
==================


B.1. Device SIO (IP Smart IO)
-----------------------------

    <Device vendor='Digimat' model='SIO' />

Il est possible de définir avec l'attribut "watchdog" un délai (en secondes) après lequel le device
appliquera les états par défaut en cas de perte de communication. 

    <Device vendor='Digimat' model='SIO' watchdog='60' />

Ce device offre un accès aux 4 entrées DI0 à DI3, 4 sorties DO0 à DO3, 4 sorties digitales DO0 à
DO3, 4 entrées analogiques universelles AI0 à AI3, et 4 sorties analogiques AO0 à AO4. Le SIO offre
également l'accès R/W aux 3 leds R,G,B.

Le device SIO peut prendre en charge plusieurs cartes d'extensions (E/S), identiques à la carte de
base si ce n'est qu'elles ne sont pas équipées de contrôleur. Un SIO avec 2 cartes (1 carte de base
+ 1 carte d'extension) est configuré à l'aide de l'attribut "boards='2'" (2 cartes au total dans
notre exemple)

    <Device vendor='Digimat' model='SIO' boards='2' />

Les E/S sorties supplémentaires sont simplement rajoutées après les variables de la carte de base.
Le principe utilisé est tout a fait similaire à celui appliqué aux modules MetzConnect. Par exemple,
le SIO déclaré ci-dessus dispose de 8 (=4+4) entrées digitales DI0 à DI7.

Un gateway digimat/sio contient implicitement un device 1 qui expose l'ensemble de se propres
variables (carte de base + extensions). 

    MBIOGateway(sio=192.168.0.248, 1 devices, OPEN)
    └── MBIODeviceDigimatSIO(sio_mb1=Digimat/SIO, ONLINE)
        ├── MBIOValueDigital(sio_mb1_comerr=False)
        ├── MBIOValue(sio_mb1_ai0=21.75C, 0s)
        ├── MBIOValue(sio_mb1_ai1=137.9ppm, 0s)
        ├── MBIOValue(sio_mb1_ai2=0.61V, 0s)
        ├── MBIOValue(sio_mb1_ai3=0.7V, 0s)
        ├── MBIOValue(sio_mb1_ai4=0.0C, 0s)
        ├── MBIOValue(sio_mb1_ai5=0.0C, 0s)
        ├── MBIOValue(sio_mb1_ai6=0.0C, 0s)
        ├── MBIOValue(sio_mb1_ai7=0.0C, 0s)
        ├── MBIOValueDigital(sio_mb1_di0=False, 0s)
        ├── MBIOValueDigital(sio_mb1_di1=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di2=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di3=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di4=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di5=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di6=True, 0s)
        ├── MBIOValueDigital(sio_mb1_di7=True, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do0=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do1=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do2=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do3=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do4=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do5=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do6=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_do7=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledb0=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledb1=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledg0=True, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledg1=False, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledr0=True, 0s)
        ├── MBIOValueDigitalWritable(sio_mb1_ledr1=True, 0s)
        ├── MBIOValueWritable(sio_mb1_ao0=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao1=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao2=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao3=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao4=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao5=7.0%, 0s)
        ├── MBIOValueWritable(sio_mb1_ao6=7.0%, 0s)
        └── MBIOValueWritable(sio_mb1_ao7=0%, 0s)

Il est possible de configurer séparément chaque entrée/sortie. Les canaux non mentionnés sont
activés par défaut, configurés avec une configuration de base. Les entrées digitales DI0 à DIn sont
configurées de la manière suivante

    <Device vendor='Digimat' model='sio' address='1' boards='2'>
        <DI0 enable='false'/>
        <DI1 invert='true'/>
    </Device>

L'attribut "enable" permet de désactiver (désinstaller) une entrée. Cette entrée ne générera plus de
trafic réseau. L'attribut "invert" permet d'inverser la polarité de l'entrée.

Les sorties digitales DO0 à DOn sont configurées de la manière suivante

    <DO0 enable='false'/>
    <DO1 invert='true' default='true'/>
    <DO3 default='false'/>

L'attribut "invert" permet d'inverser la polarité de la sortie (un état EN provoquera la mise du
relai en position OFF).  L'attribut "default" permet la définition de la valeur par défaut qui sera
appliquée sur le relai en cas de perte de communication (voir attribut "watchdog" sur le device).
Contrairement aux devices MetzConnect, seules les sorties disposant d'un état par défaut
appliquerons l'état par défaut en cas de perte de communication. Les autres resteront dans leur
dernier état, même si le watchdog est activé (comportament à choix). Si non précisé, il n'y a pas de
valeur par défaut appliquée sur une sortie.

Les entrées analogiques AI0 à AIn sont configurées de la manière suivante

    <AI0 type='pt1000' resolution='0.1' />
    <AI2 enable='false' />

L'attribut "enable" permet de désactiver (désinstaller) une entrée. Cette entrée ne générera plus de
trafic réseau. L'attribut "type" permet de définir le type de l'entrée (physique) : 

    -- unité "C" implicite pour les types : pt100, pt1000, ni1000, ntc
    -- unité "%" implicite pour les types : 20ma, 100%, 0-100%, 20-100%
    -- unité "V" implicite pour les types : 10v, 0-10v, 2-10v
    -- unité "omh" implicite pour les types : ohm (base rtd), ohm10k (base ntc)

Les types mentionnés ci-dessus sont interprétés directement par le module SIO : une entrée
configurée en mode pt1000 fourni directement une valeur en °C calculée en interne par le module SIO.
Le processeur MBIO est capable de fournir lui-même les fonctions de conversion spécifiques suivantes
(auquel cas le module est configuré pour fournir une valeur brute en [ohm] qui sera convertie par le
processeur MBIO (fonctions de conversions "CPU Digimat") :

-- +pt1000
-- +pt100
-- +ni1000
-- +ni1000-5k

Pour les types "20ma" ou "10v", l'attribut complémentaire "unit" permet de définir l'unité de la
valeur mesurée (string ou numéro). Les attributs "y0" (defaut 0) et "y1" (defaut 10) permettent de
définir une courbe de compensation vmin->y0, vmax->xy. Une sonde -50C..150C sur un signal 0-10V sera
donc configurée ainsi

    <AI1 type='10v' y0='-50' y1='150' unit='C'/>
    <AI1 type='pt1000' offset='-1.0'/>

Les attributs "x0", "x1", "y0" et "y1" permettent de spécifier la gamme utile du signal d'entrée (par défaut
x0=0 et x1=10). Si le type est '2-10V', (x0, y1) est implicitement configuré comme (2, 10). Si le type 
est '20-100%', (x0, y1) est implicitement configuré comme (20, 100).

Le type "pot" permet de définir une fonction de conversion lineaire "libre" à partir d'une mesure
ohmique (l'entrée sera implicitement configurée pour une lecture ohmique)

    <AI1 type='pot' unit='C' x0='100' y0='-3.0' x1='1000' y1='3.0' />

L'attribut résolution permet de déterminer la résolution analogique déclenchant les notifications
(changement d'état), par défaut 0.1C. L'attribut "offset" permet de déclarer un offset (positif ou
négatif) qui sera ajouté systématiquement sur la valeur finale. L'attribut "voffset" permet de
déclarer un offset qui sera systématiquement ajouté à la valeur mesurée par le module SIO (V ou ohms).

Les sorties analogiques AO0 à A0n sont configurées de la manière suivante

<AO0 lrange='50' hrange='80' default='100' />
    <AO1 min='10' max='70' resolution='5' />
    <AO2 enable='false' />

L'attribut "enable" permet de désactiver (désinstaller) une sortie. Cette sortie ne générera plus de
trafic réseau et la synchronisation (sync) des données peut être désactivée (limitation du trafic
ModBusRTU). L'attribut "default" permet la définition de la valeur par défaut qui sera appliquée sur
la sortie en cas de perte de communication (voir attribut "watchdog" sur le device).  Contrairement
aux devices MetzConnect, seules les sorties disposant d'un état par défaut appliquerons l'état par
défaut en cas de perte de communication. Les autres resteront dans leur dernier état, même si le
watchdog est activé (comportament à choix). Si non précisé, il n'y a pas de valeur par défaut
appliquée sur une sortie. Les attributs "lrange" (default 0) et "hrange" (default 100) permettent de
déclarer les zones mortes (signal utilisable effectif 0%=lrange, 100%=hrange). Le pilotage d'une
sortie 2 à 10V sera donc configurée avec l'attribut lrange=20. Les attributs "min" (defaut 0) et
"max" (defaut 100) permettent de définir les limites basses/hautes de la valeur autorisée (après
application des zones mortes). L'attribut résolution permet de déterminer la résolution analogique
déclenchant les notifications (changement d'état), par défaut 1%.

L'attribut "invert" permet d'inverser le sens d'action d'une sortie AO (0%=10V, 100%=0V).

Ce device déclare les variables "systèmes" suivantes

    -- sio_1_comerr : TRUE s'il y a un erreur de communication avec ce device

A noter que si le device est en erreur (par exemple pas de communication), alors toutes les
variables voient leur flag d'état ERROR activés. L'état des 3 leds sont lisibles et manipulables via
leurs variables associées sio_1_ledr0, sio_1_ledg0, sio_1_ledb0, ...

Le port RS485 du module SIO est exposé comme un gateway ModBus-TCP sur le port spécifique 501.

    <Gateway name='sio1gw' host='192.168.0.248' port='501' >
        ...
    </Gateway>

L'adresse IP ("host") peut utiliser le name du gateway SIO pour éviter de devoir répéter l'adresse
IP déjà précisée dans la configuration du gateway SIO

    <Gateway name='sio1gw' host='sio1' port='501' >
        ...
    </Gateway>

Le port RS485 est donc présenté comme un gateway totalement autonome (non lié au module SIO) du
point de vue du processeur MBIO. Dès lors, ce gateway est librement configurable comme un gateway
usuel (utilise un port spécifique 501 qui doit être précisé alors qu'un gateway usuel utilise un
port standard 502).

    <Gateway name='sio1gw' host='sio1' port='501' >
        <Device vendor='MetzConnect' model='DO4' address='1'/>
    </Gateway>

Cette configuration produira les variable MBIO suivantes

    MBIOGateway(sio1gw=192.168.0.186:501, 1 devices, OPEN)
    ├── MBIOValueDigital(sio1gw_comerr=OFF, 0s, #1)
    └── MBIODeviceMetzConnectMRDO4(sio1gw_mb1=METZ CONNECT GmbH/MR-DO4, ONLINE)
        ├── MBIOValueDigital(sio1gw_mb1_override=OFF, 0s, #1)
        ├── MBIOValueDigitalWritable(sio1gw_mb1_do0=OFF, flags=[CW!], 0s, #1)
        ├── MBIOValueDigitalWritable(sio1gw_mb1_do1=OFF, flags=[CW!], 0s, #1)
        ├── MBIOValueDigitalWritable(sio1gw_mb1_do2=OFF, flags=[CW!], 0s, #1)
        ├── MBIOValueDigitalWritable(sio1gw_mb1_do3=OFF, flags=[CW!], 0s, #1)
        └── MBIOValueDigital(sio1gw_mb1_comerr=OFF, 0s, #1)



C. Devices Belimo
=================


C.1. Device P22RTH
------------------

    <Device vendor='Belimo' model='P22RTH' address='20' />

Il est possible de modifier la couleur de fond (light/dark) avec l'attribut "theme" (light par
defaut)

    <Device vendor='Belimo' model='P22RTH' address='20' theme='dark' readonly='False'>

Il est possible de désactiver globalement toute commande utilisateur avec l'attribut "readonly"

    <Device vendor='Belimo' model='P22RTH' address='20' readonly='True'>

Les variables exposées par ce device dépendent de sa configuration. Les sondes sont exposées dans
les variables "t" (température), "hr" (hygrométrie) et "co2" (0 si indisponible). Le calcul du point
de rosée est exposé dans la variable "dewp". Il est possible d'activer dynamiquement le mode
readonly avec la variable du même nom.

    MBIODeviceBelimoP22RTH(gw1_mb20=Belimo/241, ONLINE)
    ├── MBIOValue(gw1_mb20_co2=580ppm, 0s)
    ├── MBIOValue(gw1_mb20_dewp=6.16C, 0s)
    ├── MBIOValue(gw1_mb20_hr=41.27%, 0s)
    ├── MBIOValue(gw1_mb20_t=19.68C, 0s)
    ├── MBIOValueDigital(gw1_mb20_co2alarm=False, 0s)
    ├── MBIOValueDigital(gw1_mb20_comerr=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_cooling=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_heating=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_readonly=False)
    └── MBIOValueWritable(gw1_mb20_spt=21.5C, 0s)
    └── MBIOValueWritable(gw1_mb20_sptx=-0.5C, 0s)

L'affichage peut être personnalisé avec des balises/attributs

    <Device vendor='Belimo' model='P22RTH' address='20' theme='light'>
        <Temperature/>
        <Hygrometry/>
        <Icons/>
        <Setpoint range='3' zero='22'/>
        <Fan boost='True' stages='3' />
    </Device>

a) L'affichage de la mesure de la température est provoquée par la balise

        <Temperature />

   Il est possible d'introduire un offset sur la mesure de la température ambiante
   avec l'attribut "offset" (positif ou négatif) 

        <Temperature offset='3.5' />

b) L'affichage de la mesure de l'hygrométrie est provoquée par la balise

        <Hygrometry />

c) L'affichage de la mesure de la qualité d'air est provoquée par la balise

        <IAQ />

   L'attribut "led" permet d'activer la LED d'état IAQ sur la sonde 

        <IAQ led='True' />

   Les seuils d'alarmes peuvent être définis avec les atributs "iaqwarning" (defaut 800) et "iaqalarm" (defaut 1200)

        <IAQ iaqwarning='1000' iaqalarm='1500' />

   L'état d'alarme IAQ est mis a disposition dans la variable TOR "co2alarm".

d) L'affichage des icônes d'état cooling/heating est activée par la balise

        <Icons />

   Ces états (R/W) sont alors mis à disposition dans les variables TOR "cooling" et "heating".
   L'usage typique est d'activer ces variables en fonction de l'ouverture des vannes respectives.

e) L'activation de la gestion du point de consigne (température) est réalisée par la balise 

        <Setpoint relative='false' zero='22.0' range='3.0'/>
        <Setpoint relative='true' range='3.0'/>

   Le point de consigne est mis à disposition dans la variable R/W "spT".

   La variable spTx calcule le point de consigne équivalent complémentaire. Si le point de consigne
   est déclaré en mode absolu, le point de consigne complémentaire est le point de consigne relatif. Si
   le point de consigne est déclaré en mode relatif, le point de consigne complémentaire est le point
   de consigne absolu. Pour pouvoir calculer le point de consigne absolu à partir du point de consigne
   relatif, il faut préciser le point zéro. Dès lors, la configuration du point de consigne en mode
   relatif devrait inclure l'attribut 'zero' pout définir la valeur de consigne "à zéro" (par défaut,
   cette valeur est définie à 22°C)

        <Setpoint relative='true' zero='22.0' range='3.0' />

f) L'activation de la gestion du point de consigne ventilateur est réalisée par la balise 

        <Fan stages='3' />

   Le nombre d'étages est défini par l'attribut "stage" (defaut 3, min=3, max=4). 
   La vitesse du ventilateur est mise à disposition dans la variable R/W "fanspeed".
   Le mode AUTO du ventilateur est mis a dispositon dans la variable R/W "auto". 

g) Le bouton ON/OFF peut être activé avec la balise

        <OnOff />

   Cela active le bouton ON-OFF et crée une variable TOR writable "onoff". L'état de la variable
   représente le mode de fonctionnement actuel (EN=mode actif, HORS=mode inactif). Il est possible
   de modifier l'état du bouton à distance en écrivant dans la variable "onoff" (EN=mode ON,
   HORS=mode OFF). En mode OFF, la consigne ventilation est forcée à 0 par la sonde et la variable
   fanauto est forcée à OFF.

g) Le bouton BOOST peut être activé avec la balise

        <Boost delay='30'/>

   Cela active le bouton BOOST. Lorsque le bouton BOOST est pressé, la consigne ventilation est 
   forcée à la valeur maximum par la sonde. Après un délai défini en minutes (max 60 minutes), le
   mode BOOST est automatiquement désactivé et la consigne vitesse revient sur sa position initiale.
   Tant que le mode BOOST est actif, la variable fanauto est forcé à OFF.


C.2. Device Actuator
--------------------

Le processeur MBIO peut gérer des servo-moteurs Belimo (vanne, clappet)

    <Device vendor='Belimo' model='Actuator' address='21'>
        <SP source='bus' />
    </Device>

Doc a venir


D. Devices EBM
=================


D.1. Device BASE
----------------

    <Device vendor='EBM' model='BASE' address='1'>
        ...
    </Device>

Lorsque le moteur supporte une fonction de libération (autorisation de mise en marche), il faut le
mentionner et indiquer d'où provient le signal de libération. Les sources suivantes sont possibles
pour le signal de libération (disponibilité dépendante des fonctionalités offertes par le moteur).
La variable "enable" met à disposition l'état du signal enable (variable writable pour la source
"bus").

    none       aucune fonction de libération implémentée
    bus        libération donnée par le bus RS485 (variable "enable")
    di1-off    libération sur entrée DIN1 (1ere entrée) à l'état OFF
    di2-off    libération sur entrée DIN2 (2ème entrée) à l'état OFF
    di3-off    libération sur entrée DIN3 (3ème entrée) à l'état OFF
    di1-on     libération sur entrée DIN1 (1ère entrée) à l'état ON
    di1        idem di1-on
    di2-on     libération sur entrée DIN2 (2ème entrée) à l'état ON
    di2        idem di2-on

    <Device vendor='EBM' model='BASE' address='1'>
        <Enable source='bus'/>
    </Device>

Outre le critère de libération (optionnel), le principe de commande de la vitesse moteur doit être
défini avec la balise "speed". 

    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='bus' control='speed' ramp='60'>
    </Device>

L'attribut "ramp" permet de configurer une rampe d'accelération/décelération (s). Les attributs
"ramp1" et "ramp0" permettent de configurer un rampe d'accélération et de décélération distinctes
(s).

Les sources de consigne vitesse suivantes sont possibles

    bus        consigne vitesse donnée par le bus RS485 (variable "sp" -- setpoint)
    ai1        consigne vitesse donnée par l'entrée AI1 (1ère entrée)
    ai2        consigne vitesse donnée par l'entrée AI2 (2ème entrée)

L'attribut "control" permet de définir le mode de contrôle de la vitesse moteur

   speed       la consigne de vitesse représente la vitesse directe souhaitée (bus ou ai1/ai2)
   sensor      la consigne de vitesse est déterminée par la mesure de sensors externes (ai1/ai2)

Le réglage de la caractéristique du signal de commande vitesse analogique est configurable par la
balise "input". Pour un signal de commande 1V ou moins=0% et 10V=100%, la configuration est la
suivante

    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='ai1' control='speed' ramp='60'>
            <Input x0='1' y0='0' x1='10' y1='100' />
        </Speed>
    </Device>

Le mode sensor peut être "détourné" puisqu'il permet de fournir au moteur 1 ou 2 signaux de
commandes analogiques qui seront "interprétés" par le moteur pour déterminer la consigne vitesse. Le
mode sensor correspond normalement à un pilotage par une sonde de température, par exemple, le
régulateur étant alors fourni par le moteur. Dans le cas MBIO, le régulateur est forcément externe
(automate). Dès lors, le mode sensor permet par exemple de fournir 2 sources de signaux analogiques
et de faire en sorte que la consigne vitesse soit issue d'un calcul (par exemple max) sur les 2
signaux.

    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='ai1' control='sensor' ramp='60'>
            <Input x0='1' y0='0' x1='10' y1='100' />
        </Speed>
    </Device>

Les sources suivantes sont disponibles en mode control='sensor'

    ai1        consigne vitesse donnée par l'entrée AI1 (1ère entrée)
    ai2        consigne vitesse donnée par l'entrée AI2 (2ème entrée)
    max        consigne vitesse données par max(ai1 ai2)
    min        consigne vitesse données par min(ai1 ai2)
    mean       consigne vitesse données par mean(ai1 ai2)

Certains moteurs permettent de configurer un watchdog sur la commande vitesse. En cas de défaillance
de la commande vitesse, une consigne pré-déterminée ("sp") est automatiquement appliquée par le moteur

    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='bus' control='speed' ramp='60'>
            <Watchdog source='bus' delay='15' sp='0' />
        </Speed>
    </Device>

La vitesse minimum/maximum du moteur autorisée (consigne %) peut être limitée avec les attributs
"min" (par r défaut 5%) et "max" (par défaut 100%). Le moteur peut ne pas fonctionner correctement
en dessous de 5%.

    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='ai1' control='speed' min='5' max='80'>
            ...
        </Speed>
    </Device>

Si la source du watchdog est "bus", le déclencheur est le temps (s) de non communication. Si la
source est "ai1" ou "ai", le déclencheur est la surveillance du niveau minimum du signal ("min") de
commande
 
    <Device vendor='EBM' model='BASE' address='1'>
        <Speed source='ai1' control='speed' ramp='60'>
            <Watchdog source='ai1' min='1' sp='0' />
        </Speed>
    </Device>

Certaines E/S du moteur sont configurables avec les balises "io1, io2 et io3" (voir possibilités
offertes par le moteur).

    <Device vendor='EBM' model='BASE' address='1'>
        <IO1 type='di|ai' />
        <IO2 type='di|ai' />
        <IO3 type='di|di!|ao' />
    </Device>

Le type "di!" correspond à une configuration DIN avec inversion de polarité. 

Certains moteurs peuvent fournir une source d'alimentation configurable entre 3.3V à 24V,
paramétrable avec la balise "vout" dont la tension est définie en [V] par l'attribut "value"

    <Device vendor='EBM' model='BASE' address='1'>
        <VOUT value='6.6' />
    </Device>

Les variables exposées par ce device dépendent de sa configuration

    MBIODeviceEBM(gw1_mb1=EBM/BASE, ONLINE)
    ├── MBIOValue(gw1_mb1_dci=0.0A, 1s, #1)
    ├── MBIOValue(gw1_mb1_ene=0kWh, 1s, #1)
    ├── MBIOValue(gw1_mb1_hcnt=35h, 1s, #1)
    ├── MBIOValue(gw1_mb1_pow=2.77W, 1s, #2)
    ├── MBIOValue(gw1_mb1_rpm=360.0t/min, 1s, #5)
    ├── MBIOValue(gw1_mb1_speed=11%, 1s, #4)
    ├── MBIOValue(gw1_mb1_status=0, 1s, #1)
    ├── MBIOValue(gw1_mb1_t1=29C, 1s, #1)
    ├── MBIOValue(gw1_mb1_t2=168C, 1s, #1)
    ├── MBIOValue(gw1_mb1_t3=35C, 1s, #1)
    ├── MBIOValue(gw1_mb1_warning=0, 1s, #1)
    ├── MBIOValueDigital(gw1_mb1_clockwise=False, 1707594207s, #1)
    ├── MBIOValueDigital(gw1_mb1_comerr=False, 1707594207s, #1)
    └── MBIOValueWritable(gw1_mb1_sp=10.0%, flags=[W], 17s, #2)


E. Devices Sensortec
====================


E.1. Device EL-D
----------------

    <Device vendor='Sensortec' model='ELD' address='16' />

Il est possible de modifier la couleur de fond (light/dark) avec l'attribut "theme" (light par
defaut). L'intensité de l'écran peut être influencé par l'attribut "brightness" (0%-100%, par défaut
100%). Le temps d'activation du rétro-éclairage est modifiable avec l'attribut "backlight" (5s-15s,
par défaut 15s).  Le temps avant extinction automatique de l'écran est modifiable avec l'attribut
"standby" (1s-60s, par défaut 60s). Enfin, l'attribut "proximity" permet de modifier la distance
approximative de la détection de mouvement pour le réveil de l'écran (0-100cm, par défaut 100cm)

    <Device vendor='Sensortec' model='ELD' address='20' theme='dark' 
        bightness='100' 
        backlight='60' 
        standby='60'
        proximity='100'>

Les variables exposées par ce device dépendent de sa configuration. Les sondes sont exposées dans
les variables "t" (température), "hr" (hygrométrie), "co2" (0 si indisponible) et "cov" (0 si
indisponible). Le calcul du point de rosée est exposé dans la variable "dewp".

L'affichage peut être personnalisé avec des balises/attributs

    <Device vendor='Sensortec' model='ELD' address='16'>
        <Temperature/>
        <Hygrometry/>
        <CO2/>
        <COV/>
        <Setpoint range='3' zero='22'/>
        <Fan stages='3' />
        <Occupancy/>
        <Icons/>
    </Device>

a) L'affichage de la mesure de la température est provoquée par la balise

        <Temperature />

   Il est possible d'introduire un offset sur la mesure de la température ambiante
   avec l'attribut "offset" (positif ou négatif) 

        <Temperature offset='3.5' />

b) L'affichage de la mesure de l'hygrométrie est provoquée par la balise

        <Hygrometry />

c) L'affichage de la mesure de la qualité d'air (CO2/COV)

La sonde peut être équipée de capteurs CO2 ou COV (Composés Organiques Volatils). Ces mesures sont
activées par les balises "co2" et "cov".

        <CO2 warning='1000' alarm='1200' hidden='false' />
        <COV warning='100' alarm='300' />

Les attributs "warning" et "alarm" définissent les seuils (en ppm pour le CO2, ppb pour le COV) qui
piloteront les indicateurs visuels sur l'écran (smileys, LED) et les variables d'alarmes MBIO.
L'attribut "hidden" permet de masquer la valeur sur l'écran LCD tout en conservant la mesure MBIO.

Si la qualité d'air est activée (CO2 ou COV), les variables suivantes sont disponibles :
- `iaq` : Indice de qualité d'air global.
- `iaqwarning` (DI) : True si seuil warning dépassé.
- `iaqalarm` (DI) : True si seuil alarme dépassé.


    MBIODeviceSensortecELD(gw1_mb16=Sensortec/EL-D-THC-MB, ONLINE)
    ├── MBIOValue(gw1_mb16_t=22.1C, flags=[C], 5s, #1)
    ├── MBIOValue(gw1_mb16_hr=34%, 5s, #1)
    ├── MBIOValue(gw1_mb16_dewp=14.7C, 5s, #1)
    ├── MBIOValue(gw1_mb16_co2=456ppm, 5s, #1)
    ├── MBIOValueDigital(gw1_mb16_iaqwarning=OFF, 5s, #1)
    ├── MBIOValueDigital(gw1_mb16_iaqalarm=OFF, 5s, #1)
    ├── MBIOValue(gw1_mb16_iaq=0, 5s, #1)
    ├── MBIOValueWritable(gw1_mb16_spt=1.5C, flags=[CW!], 5s, #1)
    ├── MBIOValue(gw1_mb16_sptx=23.5C, 5s, #1)
    ├── MBIOValueDigitalWritable(gw1_mb16_fanauto=ON, flags=[W!], 5s, #1)
    ├── MBIOValueWritable(gw1_mb16_fanspeed=0.0, flags=[CW!], 5s, #1)
    ├── MBIOValueDigitalWritable(gw1_mb16_cooling=OFF, flags=[W!], 5s, #1)
    ├── MBIOValueDigitalWritable(gw1_mb16_heating=OFF, flags=[W!], 5s, #1)
    └── MBIOValueDigital(gw1_mb16_comerr=OFF, 0s, #1)

    MBIODeviceBelimoP22RTH(gw1_mb20=Belimo/241, ONLINE)
    ├── MBIOValue(gw1_mb20_co2=580ppm, 0s)
    ├── MBIOValue(gw1_mb20_dewp=6.16C, 0s)
    ├── MBIOValue(gw1_mb20_hr=41.27%, 0s)
    ├── MBIOValue(gw1_mb20_t=19.68C, 0s)
    ├── MBIOValueDigital(gw1_mb20_co2alarm=False, 0s)
    ├── MBIOValueDigital(gw1_mb20_comerr=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_cooling=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_heating=False)
    ├── MBIOValueDigitalWritable(gw1_mb20_readonly=False)
    ├── MBIOValueWritable(gw1_mb20_spt=21.5C, 0s)
    └── MBIOValueWritable(gw1_mb20_sptx=-0.5C, 0s)

*********************** EN COURS DE REDACTION **********************

d) L'affichage des icônes d'état cooling/heating est activée par la balise

        <Icons />

   Ces états (R/W) sont alors mis à disposition dans les variables TOR "cooling" et "heating".
   L'usage typique est d'activer ces variables en fonction de l'ouverture des vannes respectives.

e) L'activation de la gestion du point de consigne (température) est réalisée par la balise 

        <Setpoint relative='false' zero='22.0' range='3.0'/>
        <Setpoint relative='true' range='3.0'/>

   Le point de consigne est mis à disposition dans la variable R/W "spT".

   La variable spTx calcule le point de consigne équivalent complémentaire. Si le point de consigne
   est déclaré en mode absolu, le point de consigne complémentaire est le point de consigne relatif. Si
   le point de consigne est déclaré en mode relatif, le point de consigne complémentaire est le point
   de consigne absolu. Pour pouvoir calculer le point de consigne absolu à partir du point de consigne
   relatif, il faut préciser le point zéro. Dès lors, la configuration du point de consigne en mode
   relatif devrait inclure l'attribut 'zero' pout définir la valeur de consigne "à zéro" (par défaut,
   cette valeur est définie à 22°C)

        <Setpoint relative='true' zero='22.0' range='3.0' />


f) L'activation de la gestion du point de consigne ventilateur est réalisée par la balise 

        <Fan stages='3' />
        <Fan stages='3' boost='True' />

   Le nombre d'étages est défini par l'attribut "stage" (defaut 3, min=3, max=4). 
   Le bouton BOOST peut être activé par l'attribut TOR "boost='true'". 
   La vitesse du ventilateur est mise à disposition dans la variable R/W "fanspeed".
   Le mode AUTO du ventilateur est mis a dispositon dans la variable R/W "auto". 


E.2. Device EL (Ecran LCD simple)
---------------------------------

    <Device vendor='Sensortec' model='EL' address='17' />

Modèle simplifié disposant d'un écran mais de moins de fonctionnalités d'interface (pas de boutons,
pas de ventilateur). Il mesure la température (toujours actif) et optionnellement l'humidité et le
CO2/COV.

    <Device vendor='Sensortec' model='EL' address='17'>
        <Temperature offset='-0.5' />
        <Hygrometry />
        <CO2 warning='1000' alarm='1500' />
    </Device>

Ce device expose les variables de mesure de base (t, hr, dewp, co2, cov) ainsi que les alarmes IAQ,
mais ne dispose pas des consignes (Setpoint) ni de la gestion de ventilation.


F. Devices iSMA
===============

Les modules iSMA (Intelligent Solution Managing Automation) sont supportés via le protocole Modbus
RTU ou TCP (pour les versions IP).

F.1. Device 4I4OH (Hybrid IoT)
------------------------------

Ce module dispose de 4 entrées digitales (DI), 4 sorties digitales (DO), 4 entrées analogiques (AI)
et 4 sorties analogiques (AO).

    <Gateway ...>
        <Device vendor='Isma' model='4I4OH' address='1' />
    </Gateway>

Variables générées :

    MBIODeviceIsma4I4OH(gw1_mb1=ISMA/4I4OH, ONLINE)
    ├── MBIOValueDigital(gw1_mb1_di0=False) ... (x4)
    ├── MBIOValueDigitalWritable(gw1_mb1_do0=False) ... (x4)
    ├── MBIOValue(gw1_mb1_ai0=22.5C) ... (x4)
    ├── MBIOValueWritable(gw1_mb1_ao0=0%) ... (x4)
    └── MBIOValueDigital(gw1_mb1_override=False)

Configuration des Entrées/Sorties :

    <Device vendor='Isma' model='4I4OH' address='1'>
        <DI0 invert='true' zone='bureau' />
        <DO0 default='true' invert='false' />
        <AI0 type='pt1000' filter='10' />
        <AO0 lrange='0' hrange='100' default='0' />
    </Device>

- **DI** : Attributs `invert` (inversion logique), `enable`.
- **DO** : Attributs `invert`, `default` (état par défaut si watchdog), `enable`.
- **AI** : Attributs `type` (pt1000, ni1000, 10v, 0-10v, ohm, ...), `filter` (constante de temps
  filtre 0-60s), `offset`.
- **AO** : Attributs `default` (valeur repli), `invert` (0-10V inversé), `lrange`/`hrange`
  (mise à l'échelle).

Le module supporte le rechargement à chaud de sa configuration (reboot non nécessaire, mais
possible). Les versions IP (ex: 4I4OHIP) sont configurables de la même manière.


Service de Monitoring WEB
=========================

Le processeur MBIO peut lancer un service de monitoring WEB permettant de visualiser/manipuler les
différentes ressources (tasks, gateways, devices, values) disponibles. Par défaut, le serveur Web
est lancé sur le port 443, mais cela peut être redéfini par paramétrage (laisser les ports 8000 et
8443 disponibles pour le service de publication temporaire des firmwares).

    <Monitor/>
    <Monitor name='wsmon' port='443'/>

Le mot de passe d'accès par défaut est "mbi0", mais il est modifiable avec l'attribut 'password', en
se rappelant que le fichier de configuration XML est automatiquement converti en minuscules.

    <Monitor password='mysecret' />
 
Le service de monitoring peut offrir un accès extrene aux ressources. Dès lors, il est
important de désactiver ce service dès que les campagnes de mise en service sont terminées. De plus,
ce service consomme des ressources CPU qui peuvent être significatives, en particulier si le service
est exploité simultanément par plusieurs utilisateurs. 


Systèmes EasyBUS3
=================

Le processeur MBIO est capable de prendre en charge la gestion de systèmes EasyBUS (CCF, clapets
coupe feu ou boites de débit VAV). Un système Easybus3 est composé d'un module Easy-H (écran
tactile, interface LAN), couplé à un maximum de 3 modules Easy-M (bus). Le processeur MBIO utilise
le protocole de communication ModBusTCP pour communiquer avec le module Easy-H. Chaque bus peut
gérer un maximum de 128 devices (CCF ou VAV). Un système Easybus est déclaré avec la balise
"easybus".  L'attribut "name" permet de nommer le système (doit être unique). Ce nom sera utilisé
comme préfixe pour l'ensemble des variables associées. L'attribut "host" défini l'adresse IP du
module Easy-H.  L'attribut "port" permet de définir le port réseau du service ModbusTCP (par défaut
502)

    <Easybus name='easy1' host='192.168.0.218' port='502' >
        ...
    </Easybus>

On déclare ensuite chaque module Easy-M par la balise "bus". L'attribut "address" défini l'adresse
du bus correspondant (normalement 1, 2, 3)"

    <Easybus name='easy1' host='192.168.0.218' >

        <Bus address='1' >
            ...
        </Bus>

        <Bus address='2' >
            ...
        </Bus>

    </Easybus>

Les CCF raccordés à chaque bus sont ensuite déclarés par la balise "ccf". L'adresse de chaque CCF
est défini par l'attribut "address"

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <CCF address='1' />
            <CCF address='2' />
        </Bus>
    </Easybus>

La configuration ci-dessus produira automatiquement les variables suivantes (module "easy1", master "b1" pour "bus 1")

    MBIOGatewayEasybus(easy1=192.168.0.218, 1 devices, OPEN)
    └── MBIODeviceEasybusMaster(easy1b1=Easybus3/Easy-M, ONLINE)
        ├── MBIOValue(easy1b1_cycle=81.0ms, 0s, #764)
        ├── MBIOValue(easy1b1_slaves=2.0, 0s, #177)
        ├── MBIOValue(easy1b1_slaveserr=0.0, 0s, #177)
        ├── MBIOValueDigital(easy1b1_fire=OFF, 0s, #177)
        ├── MBIOValueDigital(easy1b1_run=ON, 0s, #177)
        ├── MBIOValueDigital(easy1b1_comerr=None, N/As, #0)
        +
        ├── MBIOValueDigital(easy1b1_ccf1_closed=OFF, 0s, #177)
        ├── MBIOValueDigital(easy1b1_ccf1_open=ON, 0s, #177)
        ├── MBIOValueDigital(easy1b1_ccf1_smoke=OFF, 0s, #177)
        ├── MBIOValueDigital(easy1b1_ccf1_err=OFF, 0s, #177)
        +
        ├── MBIOValueDigitalWritable(easy1b1_ccf1_cmd=None, flags=[EW!], N/As, #0)
        +
        ├── MBIOValueDigital(easy1b1_ccf2_closed=OFF, 0s, #177)
        ├── MBIOValueDigital(easy1b1_ccf2_open=ON, 0s, #178)
        ├── MBIOValueDigital(easy1b1_ccf2_smoke=OFF, 0s, #177)
        ├── MBIOValueDigital(easy1b1_ccf2_err=OFF, 0s, #177)
        +
        └── MBIOValueDigitalWritable(easy1b1_ccf2_cmd=None, flags=[EW!], N/As, #0)

On constate qu'un système Easybus est traité par le processeur MBIO d'une manière comparable aux
Gateways+Devices ModbusTCP. Un module Easy-H est représenté par un objet MBIOGatewayEasybus (dérivé
de l'objet MBIOGateway). Les modules Easy-M sont représentés par un objet MBIODeviceEasybusMaster
(derivé de l'objet MBIODevice).

Les premières variables (easy1b1_*) représentent les variables liées au bus 1 (module Easy-M 1)

    -- easy1b1_cycle
    temps de cycle du module Easy-M

    -- easy1b1_slaves
    nombre de slaves détectés par le module Easy-M sur le bus 

    -- easy1b1_slaveserr
    nombre de slaves détectés en erreur sur le bus par le module Easy-M

    -- easy1b1_fire
    True si le module Easy-M est est mode FEU (imposé par le module Easy-H). 
    Le mode FEU impose la fermeture des CCF

    -- easy1b1_run
    True si le module Easy-M est en mode RUN (=fonctionnement normal)

    -- easy1b1_comerr
    True si le processeur MBIO ne parvient pas à établir 
    une communication avec le module Easy-M

Viennent ensuite une série de variables associées à chaque CCF (easy1b1_ccf1_* pour le CCF 1)

    -- easy1b1_ccf1_closed
    True si le CCF est fermé

    -- easy1b1_ccf1_open
    True si le CCF est ouvert

    -- easy1b1_ccf1_smoke
    True si le détecteur de fumée cablé sur le CCF (option) est actif (feu)

    -- easy1b1_ccf1_err
    True si le CCF est déclaré en erreur par le module Easy-H 
    (pas de communication, état incohérent)

Une variable de commande, writable, (easy1b1_ccf1_cmd) est associée à chaque CCF. Cette variable
permet de piloter le CCF (True=Ouvert, False=Fermé).

A noter qu'il est possible de désactiver un système Easybus complètement ou partiellement depuis la
configuration par l'attribut "enable" sans devoir complètement l'éliminer de la configuration.
Toutes les variables dépendantes ne seront alors simplement pas déclarées.

    <Easybus name='easy1' host='192.168.0.218' enable='false'>
        <Bus address='1' enable='false' >
            <CCF address='1' enable='false' />
        </Bus>
    </Easybus>

Le processeur MBIO permet de gérer les CCF par "groupes", notion qui n'existe pas nativement sur un
système Easybus. Un groupe représente une sorte de CCF virtuel regroupant plusieurs CCF. On associe
un ou plusieurs CCF à un groupe avec la balise "group". Chaque CCF peut appartenir au groupe qu'il
veut (un groupe pouvant contenir des CCF provenant des différents bus -- modules Easy-M)

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <CCF address='1' group='a'/>
            <CCF address='2' group='a'/>
            <CCF address='3' group='b'/>
            <CCF address='4' />
        </Bus>
    </Easybus>

Dans l'exemple ci-dessus, le groupe "a" contiendra les CCF 1 et 2. Le groupe "b" contiendra le CCF 3
et le CCF 4 n'appartiendra à aucun groupe. Les noms de groupes doivent être uniques et "courts" dans
la mesure où le nom de groupe sera intégré dans le nom des variables correspondantes.

Chaque groupe fournira ses propres variables pour représenter l'état du "CCF virtuel" correspondant.
Pour le groupe "a", les variables suivantes (easy1_ccfa_*) sont disponibles

    ├── MBIOValueDigital(easy1_ccfa_closed=OFF, 0s, #177)
    ├── MBIOValueDigital(easy1_ccfa_open=ON, 0s, #178)
    ├── MBIOValueDigital(easy1_ccfa_smoke=OFF, 0s, #177)
    ├── MBIOValueDigital(easy1_ccfa_err=OFF, 0s, #177)

Ces variables renseignent sur l'état d'un groupe de CCF

    -- easy1_ccfa_closed
    True si tous les CCF du groupe "a" sont fermés

    -- easy1_ccfa_open
    True si tous les CCF du groupe "a" sont ouverts

    -- easy1_ccfa_smoke
    True si au moins un détecteur de fumée (option) cablé sur les CCF 
    du groupe "a" est actif (feu)

    -- easy1_ccfa_err
    True si au moins un CCF du groupe est déclaré en erreur 
    par le module Easy-H (pas de communication, état incohérent)

Le groupe "a" est pilotable par la variable "easy1_ccfa_cmd", writable. Cette variable permet de piloter
l'ensemble des CCF du groupe (True=Ouverts, False=Fermés). A noter que tous les CCF qui sont
associés à un groupe ne peuvent plus être pilotés individuellement. Par conséquent, les CCF associés
à un groupe ne disposent plus d'une variable de commande individuelle (easy1b1_ccf1_cmd).

Un CCF qui appartient à un groupe peut être "masqué" par le processeur MBIO avec l'attribut "hidden"
dans le sens ou il est possible de faire en sorte que ses variables d'état ne soient pas créées. Si
on ne s'intéresse qu'à l'état du groupe, cela permet alors de limiter considérablement le nombre de
variables qui seront créées

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <CCF address='1' group='a' hidden='true' />
            <CCF address='4' />
        </Bus>
    </Easybus>

Les boites de débits connectées sur un bus easybus (module Easy-V), sont déclarées d'une manière
similaire aux CCF avec une balise "vav". Les adresses 1 à 128 peuvent être utilisées par les modules
installés sur chaque bus (une adresse 1 utilisée par un CCF ne peut pas être réutilisée par une
boite VAV)

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <VAV address='10' >
                ...
            </VAV>
        </Bus>
    </Easybus>

Chaque module Easy-V peut gérer 2 boites VAV (déclarées avec les balises "device") et 4 sensors (0-10V
ou resistifs) que l'on peut déclarer avec les balises "sensor". L'attribut "address" permet de
pointer vers le "bornier" souhaité (attention : numérotation de 0)

    VAV1      <Device address='0' />
    VAV2      <Device address='1' />
    Sensor1   <Sensor address='0' />
    Sensor2   <Sensor address='1' />
    Sensor3   <Sensor address='2' />
    Sensor4   <Sensor address='3' />

Le calcul des consignes (%) et du débit effectif (%, m3/h) d'une boite de débit impose de connaitre
les 3 caractéritisques suivantes, à préciser (obligatoire) pour chaque VAV (device)

    vmin      débit minimum de la boite (m3/h)
    vmax      débit maximum de la boite (m3/h) vmax>vmin
    vnom      débit minimum de la boite (m3/h), vnom>=vmax

Seules les VAV déclarées ("device") produisent des variables MBIO. Par exemple, si seule la VAV1 est
connectée sur le module Easy-V 10, la déclaration suivante est plausible

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <VAV address='10' >
                <Device address='0' vmin='200' vmax='800' vnom='1400' />
            </VAV>
        </Bus>
    </Easybus>

Cette configuration produira les variables MBIO suivantes

    ├── MBIOValue(easy1b1_vav10.0_v=0.0m3/h, 2s, #1)
    ├── MBIOValue(easy1b1_vav10.0_vr=0%, flags=[C], 2s, #1)
    └── MBIOValueWritable(easy1b1_vav10.0_sp=44%, flags=[CW], 2s, #1) 

Le module Easy-V 10 du bus 1 produira des variables "easyb1_vav10*". La boite VAV1 produira des
variables "_vav10.0*" tandis que la boites VAV2 produira des variables "_vav10.1*".

    -- easy1b1_vav10.0_v 
    Débit effectif de la boite VAV1 (m3/h), calculé à partir de vmin/vmax

    -- easy1b1_vav10.0_vr
    Débit effectif relatif de la boite VAV1 (m3/h), calculé à partir de vmin/vmax
    0% si débit <= vmin, 100% si débit >= vmax 

    -- easy1b1_vav10.0_sp
    Point de consigne (%) de la boite de débit. 
    0% = boite fermée, 0.5%-100% = vmin..vmax

Il est possible de remonter dans des variables MBIO les caractéristiques de débit avec l'attribut
"showconfig" (False par défaut)

    <Device address='0' vmin='200' vmax='800' vnom='1400' showconfig='True' />

cela produira les variable MBIO complémentaires suivantes

    -- easy1b1_vav10.0_vmin 
    Débit minimum de la boite VAV1 (m3/h)

    -- easy1b1_vav10.0_vmax 
    Débit maximum de la boite VAV1 (m3/h)

    -- easy1b1_vav10.0_vnom 
    Débit nominal de la boite VAV1 (m3/h)


Les sensors raccordés sur le module Easy-V (0..3) sont déclarés (balise "sensor"). Les sensors non
déclarés ne produisent aucune variable MBIO

    <Easybus name='easy1' host='192.168.0.218' >
        <Bus address='1' >
            <VAV address='10' >
                <Device address='0' vmin='200' vmax='800' vnom='1400' />
                <Sensor address='0' type='pt1000' />
                <Sensor address='1' type='10v' y0='-50' y1='150' unit='C' />
            </VAV>
        </Bus>
    </Easybus>

Les types suivants sont supportés (R=Resistive mode, V=Voltage mode)

    pt100      [R]   Sonde PT100, unité C implicite
    pt1000     [R]   Sonde PT1000, unité C implicite
    ni1000     [R]   Sonde Ni1000, unité C implicite
    ni1000-5k  [R]   Sonde Ni1000-TK5000, unité C implicite
    ohm        [R]   Mesure ohmique
    pot        [R]   Mesure ohmique, unité à préciser (unit),
                     Points (x0, y0) et (y0, y1) à préciser 
                     avec les attributs "x0" (ohms), "y0" (unit),
                     "x1" (ohms), "y1" (unit) 
    10v        [V]   0-10 unité à préciser (unit), 
                     valeurs limites 0V->"y0" et 10V->"y1" à préciser

L'attribut "offset" permet d'ajouter un offset (positif/négatif) aux valeurs calculées

    <Sensor address='0' type='pt1000' offset='-1.5' />

Chaque sensor déclaré produit une variable MBIO "ai" correspondante
 
    ├── MBIOValue(easy1b1_vav10.0_ai0=23.9C, flags=[C], 2s, #1)

Enfin, une variable générale associée au module Easy-H (easy1_comerr) est fournie par le processeur
MBIO pour signaler s'il y a un problème de communication réseau avec le module.


Variables Virtuelles
====================

Le processeur MBIO peut déclarer des variables virtuelle "writables" en utilisant des balises
"virtualio"

    <Config>
        ...
        <VirtualIO name='vio'>
            <Digital name='mystate' />
            <Analog name='text' unit='C' resolution='0.1' />
        </VirtualIO>
        ...
    </Config>

Dans l'exemple ci-dessus, les variables suivantes vont être créés, par exemple pour permettre
d'injecter dans le monde MBIO la température extérieure (text) disponible dans un automate

    MBIOTaskVirtualIO(vio, RUN)
    └── MBIOValueWritable(vio_text=21.2C, 5s, #1)
    └── MBIODigitalValueWritable(vio_mystate=None, 0s, #1)

Il peut y avoir autant de balises VirtualIO que nécessaires, toutes devant avoir un nom distinct.
Chaque balise VirtualIO est implémentée par une MBIOTask, servant de namespace. Toutes les variables
déclarées avec les attributs digital et analog sont obligatoirement "writable". La mise à jour des
valeurs doit être assurée par "quelqu'un" (CPU). La tâche VirtualIO se charge "simplement" de
transmettre les changements d'états aux abonnés.

La balise "variable" permet d'implémenter des variables readonly dont la valeur est calculée à
partir d'une expression python pouvant contenir des noms de variables MBIO.

    <VirtualIO name='vio'>
        <Variable name='x' unit='C' resolution='0.1' 
            expression='gw1_mb20_t * 2.0 + mys_sw1_t' /> 
    </VirtualIO>

L'unité de la variable est définie par l'attribut "unit", et sa valeur est calculée
selon l'expression donnée par l'attribut "expression". L'expression peut contenir plusieurs
variables différentes ainsi que du code au format Python. La variable déclarée ci-dessus produira
la variable MBIO suivante 

    MBIOTaskVirtualIO(vio, RUN)
    └── MBIOValueWritable(vio_x=72.0C, 5s, #1)

A noter qu'il est possible de "borner" ou d'interpoler la valeur calculée de la variable en
fournissant une "courbe de compensation" définie par 2 points (x0,y0):(x1:y1)

    <VirtualIO name='vio'>
        <Variable name='x' unit='%' resolution='1' 
            expression='gw1_mb20_t * 2.0' 
            x0='0' y0='0' x1='40' y1='100' />
    </VirtualIO>


Schedulers
==========

Le processeur MBIO peut gérer des programmes horaires en utilisant des balises "scheduler". Un
scheduler contient un ou plusieurs "program" nommés (name) qui contiennent des "triggers" (on/off).

Un trigger est configuré pour un ou plusieurs jours de la semaine avec l'attribut "dow" (1=lundi,
2=mardi, ...  7=dimanche). Un trigger peut être affecté à plusieurs jours : "1236" pour
lundi-mercredi + samedi, "*" pour n'importe quel jour. Si plusieurs triggers sont déclarés pour la
même date (dow+time), les triggers "multi-jours" sont considérés comme moins prioritaires. Un
trigger avec dow="*" est toujours le moins prioritaire de tous.  L'attribut "time" permet de
spécifier l'heure de l'action (08h00, 08:00, 8, 08h). 

    <Config>
        ...
        <Scheduler name='sch'>

            <Program name='A'>
                <Triggers>

                    <On dow='*' time='08h00'/>
                    <Off dow='*' time='12h00'/>
                    <On dow='*' time='13h30'/>
                    <Off dow='*' time='18h00' />

                </Triggers>
            </Program>

            <Program name='B' />

        </Scheduler>
        ...
    </Config>

La balise "slot" permet de définir 2 triggers d'un coup (trigger ON au stamp "time", et trigger OFF
au stamp "time+duration"). Le processeur MBIO expose l'état de chaque programme horaire dans une
variable digitale distincte

    MBIOTaskScheduler(sch, RUN)
    ├── MBIOValueDigital(sch_a_state=True, 0s, #1)
    └── MBIOValueDigital(sch_b_state=False, 0s, #1)

Chaque program peut gérer plusieurs "variantes" (variant 0, 1, 2, ...). Les triggers sont associés à
une variante (0 par défaut). La variante active (0, 1, 2, ...) est définie par la variable "variant"
du scheduler

  MBIOTaskScheduler(sch, RUN)
  └── MBIOValueWritable(sch_variant=0, flags=[W!], 1s, #0)

Cette variable étant "writable", elle peut être redéfinie dynamiquement. Tous les programmes
rechargent automatiquement les triggers correspondant à la variante active. Les triggers
correspondant aux autres variantes sont ignorés.

Chaque trigger peut donc être attribué à une variante avec l'attribut "variant"

    <Triggers>
        <On dow='*' time='08h00' variant='0' />
        <On dow='*' time='09h00' variant='1' />
    </Triggers>

Un programme horaire peut gérer un ou plusieurs points de consignes (setpoint, ou "sp") qui peuvent
être modifiés par les triggers. Un setpoint défini avec la balise "setpoints". La valeur initiale
du setpoint est attribuée avec l'attribut "value"

    <Scheduler name='sch'>

        <Setpoints>
            <t unit='C' value='22' resolution='0.1' />
            <hr unit='%' value='30' />
        </Setpoints>

        <Program name='A'>
            <Triggers>
                <On dow='*' time='08h00' t='24.0' hr='50' />
                <On dow='*' time='17h30' t='18.0' />
            </Triggers>
        </Program>

    </Scheduler>

Chaque setpoint défini est automatiquement associé à une variable "du même nom"

    MBIOTaskScheduler(sch, RUN)
    ├── MBIOValue(sch_sp_hr=30.0%, 0s, #0)
    ├── MBIOValue(sch_sp_t=22.0C, 0s, #0)

Le scheduler peut également fournir des valeurs constantes

    <Scheduler name='sch'>

        <Constants>
            <T0 value='0'/>
            <T1 value='10'/>
            <T2 value='30'/>
            <T3 value='99'/>
        </Constants>

    </Scheduler>
 
qui seront automatiquement exposées dans des variables par le processeur MBIO

    MBIOTaskScheduler(sch, RUN)
    ├── MBIOValue(sch_cst_t0=0.0, 1s, #0)
    ├── MBIOValue(sch_cst_t1=10.0, 1s, #0)
    ├── MBIOValue(sch_cst_t2=30.0, 1s, #0)
    ├── MBIOValue(sch_cst_t3=99.0, 1s, #0)

Le scheduler peut être configuré pour downloader automatiquement la configuration des programmes
(Triggers, Constants) toutes les "period" minutes. La configuration interne existante est
automatiquement remplacée par la configuration téléchargée.  La balise "download" permet de définir
la source (https) de données pour la configuration des triggers. L'URL doit être encapsulée dans une
syntaxe <![CDATA[xxx]]>

    <Config>
        ...
        <Scheduler name='sch'>

            <Download type='csv' dialect='excel' separator=',' period='60'>
                <URL>
                    <![CDATA[https://www.dropbox.com/scl/fi/96mwajyr1t4addvsqzts8/
                        scheduler.csv?rlkey=whikcqbdordzxryithwnpioy6&dl=1]]>
                </URL>
            </Download>

        </Scheduler>
        ...
    </Config>

La balise "type" permet de définir le format des données a télécharger (par exemple "csv"). Lorsque
la mise à jour des triggers est configurée ("download"), une variable "comerr" est disponible. Cette
variable indique si le processus de synchronisation distant est opérationnel (download +
interpretation données sans erreurs)

    MBIOTaskScheduler(sch, RUN)
    └── MBIOValueDigital(sch_comerr=True, 4s, #1)

Les formats (balise "type") de fichiers suivants sont actuellement supportés (download)

1) type="csv"

    ON, PROGRAM, VARIANT, DOW, time [, sp] [, sp] ...
    OFF, PROGRAM, VARIANT, DOW, time [, sp] [, sp] ...
    SLOT, PROGRAM, VARIANT, DOW, start, duration [, sp] [, sp] ...

    Le champ "program" indique le nom du programme (scheduler) auquel s'applique le trigger qui
    suit. Pour les triggers "ON" et "OFF", le champ "time" indique l'heure de l'événement (8, 8:15,
    8h30). La modification des points de consignes est optionnelle (l'ordre des champs "sp" doit
    correspondre à l'ordre de déclaration des setpoints dans la configuration). Le trigger "SLOT" permet
    de définir une plage ON->OFF (création implicite d'un trigger "ON" à l'heure définie par le champ
    "start" (9h45), suivi d'un trigger "OFF" N minutes plus tard (N étant défini par le champ
    "duration"). Les triggers sont valables pour un ou plusieurs jours de la semaine mentionnés par le
    champ "dow" (*=tous les jours, 1=lundi, 2=mardi, 123=lundi+mardi+mercredi, 7=dimanche). Les espaces
    sont ignorés, les lignes vides sont ignorées.

    SET, CONSTANT_NAME, VALUE

    Permet de définir la valeur d'une constante depuis le fichier CSV.

Le contenu du fichier de configuration (csv) distant est automatiquement sauvegardé dans le
répertoire de configuration MBIO. Pour limiter le nombre d'écriture sur le disque, le fichier n'est
ré-écrit que si le contenu change. Au démarrage de la tâche Scheduler, le contenu de ce fichier
constitue la configuration initiale du scheduler.


Switchs MyStrom
===============

Le processeur MBIO peut gérer des switchs MyStrom. Chaque balise "mystrom" crée son propre
"namespace". L'attribut "refresh" permet de spécifier la periode (s) de mise à jour des données des
devices MyStrom déclarés.

Un switch MyStrom est déclaré par une balise "switch"

    <Config>
        ...
        <MyStrom name='mys' refresh='15'>
            <Switch name='sw1' ip='192.168.132.59'/>
            <Switch name='sw2' ip='192.168.132.33'/>
        </MyStrom>
        ...
    </Config>

La configuration ci dessus créera les variables suivantes

    MBIOTaskMyStromSwitch(mys, RUN)
    ├── MBIOValue(mys_sw1_pow=5.9W, 0s, #41)
    ├── MBIOValue(mys_sw1_t=21.91C, 0s, #30)
    ├── MBIOValueDigitalWritable(mys_sw1_state=True, flags=[W!], 0s, #29)
    ├── MBIOValue(mys_sw2_pow=0.0W, 3s, #29)
    ├── MBIOValue(mys_sw2_t=22.98C, 3s, #29)
    ├── MBIOValueDigitalWritable(mys_sw2_state=False, flags=[W!], 3s, #29)
    └── MBIOValueDigital(mys_comerr=False, 4s, #1)

La variable "state" permet de piloter le relai commandé. L'état de la variable "state" représente
toujours l'état actuel du relai. Lorsque le processeur MBIO ne parvient pas à dialoguer avec un
switch, les variables correspondantes sont mise en erreur. Une variable "comerr" indique s'il y a
une erreur de communication active avec au moins un des switchs déclarés dans la tâche.

Le moèle "zero" n'intègre pas de sonde de température ni de compteur d'énergie. En conséquence, les
variables "t" et "pow" ne sont pas disponibles lorsque ce modèle est utilisé. On précise le modèle
avec l'attribut "model='zero'" dans la balise "switch"

    <Switch name='sw3' ip='192.168.132.60' model='zero' />

    MBIOTaskMyStromSwitch(mys, RUN)
    └── MBIOValueDigitalWritable(mys_sw3_state=True, flags=[W!], 0s, #29)

Si le modèle n'est pas précisé, on part du principe que c'est un modèle standard (non zéro).


Switchs Shelly
===============

Le processeur MBIO peut gérer des switchs Shelly. Chaque balise "shelly" crée son propre
"namespace". L'attribut "refresh" permet de spécifier la periode (s) de mise à jour des données des
devices Shelly déclarés.

Un switch Shelly est déclaré par une balise "switch"

    <Config>
        ...
        <Shelly name='shelly' refresh='15'>
            <Switch name='sw0' ip='192.168.0.103' id='0' />
        </Shelly>
        ...
    </Config>

La configuration ci dessus créera les variables suivantes

    MBIOTaskShelly(mys, RUN)
    └── MBIOValueDigitalWritable(shelly_sw0_state=True, flags=[W!], 0s, #29)

Lorsqu'un switch contient plusieurs components (relais), il est possible de préciser le numéro du
composant souhaité avec l'attribut "id" (0 par défaut). 

    <Shelly name='shelly' refresh='15'>
        <Switch name='sw0' ip='192.168.0.103' id='0' />
        <Switch name='sw1' ip='192.168.0.103' id='1' />
    </Shelly>

La variable "state" permet de piloter le relai commandé. L'état de la variable "state" représente
toujours l'état actuel du relai. Lorsque le processeur MBIO ne parvient pas à dialoguer avec un
switch, les variables correspondantes sont mise en erreur. Une variable "comerr" indique s'il y a
une erreur de communication active avec au moins un des switchs déclarés dans la tâche.

L'état du switch peut être inversé avec l'attribut "invert". Cela inverse l'état (status) ainsi que
la commande du relai

        <Switch name='sw0' ip='192.168.0.103' id='0' invert='true' />

Le processeur MBIO peut gérer des inputs Shelly (contacts/boutons). La syntaxe déclarative est 
identique au cas du Switch, mais avec la balise "Input". Evidemment, les variables "Input" ne 
sont pas "writable"

        <Input name='in0' ip='192.168.0.105' id='0' />
        <Input name='in1' ip='192.168.0.105' id='1' invert='true' />


Sondes SensorPush
=================

Le processeur MBIO peut rappatrier des données fournies par des capteurs SensorPush
(www.sensorpush.com). Chaque balise "sensorpush" permet d'accéder à un compte SensorPush donné.
L'attribut "refresh" permet de spécifier la periode (s) de mise à jour des données des
devices MyStrom déclarés.

    <Config>
        ...
        <SensorPush name='spush' email='mbio@digimat.org' password='1234' refresh='60'>
            ...
        </SensorPush>
        ...
    </Config>

Attention : le fichier de configuration XML étant automatiquement "lowerisé" avant interprétation,
l'attribut "password" ne peut pas contenir des caractères majuscules. Si cela pose problème, le
password doit être donné encodé au format "b16" (www.hexator.com). Dans ce cas, préfixer le password
avec "(b16)", ce qui donne -- pour "helloWorld!" -- la configuration suivante

    password='(b16)68656C6C6F576F726C6421'

La tâche SensorPush propose une méthode ".b16encode(str)" qui permet de convertir aisément une
chaine au format b16

    >>> task=mbio.task('spush')
    >>> task.b16encode('helloWorld!')
    '(b16)68656C6C6F576F726C6421'

Les sensors que l'on souhaite utiliser sont déclarés avec la balise "sensor". On crée ensuite les
variables dont on a besoin en "mappant" chaque variable sur la propriété "source" fournie par le
sensor

    <SensorPush name='spush' email='me@gmail.com' password='XXX' refresh='60' >
        <Sensor id='402703.18558228621148417356' >
            <Value name='t0'  source='temperature' resolution='0.1' unit='C' />
            <Value name='hr0' source='humidity' resolution='1' unit='%' />
        </Sensor>
    </SensorPush>

La configuration ci dessus créera les variables suivantes

    MBIOTaskSensorPush(spush, RUN)
    ├── MBIOValue(spush_hr0=23.6%, 9s, #0)
    ├── MBIOValue(spush_t0=33.5C, 9s, #0)
    └── MBIOValueDigital(spush_comerr=False, 9s, #0)

Une variable "comerr" indique s'il y a une erreur de communication active avec au moins un des
sensors.


Système Philips Hue
===================

Le processeur MBIO peut gérer des devices Philips Hue connectés sur un Bridge Hue. La communication
avec le bridge est réealisée via l'API https Hue. Chaque balise "hue" permet de mettre en
communication le processeur MBIO avec un bridge. L'attribut "name" permet de créer le "namespace"
pour les variables associées. Les changements d'états sont gérés par une connexion https spécifique
avec le bridge (events). L'attribut "refresh" permet de spécifier la periode [s] de mise à jour des
données pour les devices Hue déclarés (polling régulier en plus du traitement des events). Si l'adresse
ip du bridge est fixe, il est possible de la spécifier avec l'attribut "host".

    <Config>
        ...
        <Hue name='myhue' host='192.168.0.190' refresh='60' >

        </Hue>¬
        ...
    </Config>

en principe, l'adresse du bridge est dynamiquement allouée. Le processeur peut scanner le réseau pour
rechercher les bridges disponibles (utilise l'attribut "network" de la balise principale "config")

    >>> task=mbio.tasks('hue')
    >>> task.discover()
    {'ecb5fafffe9ac5c5': '192.168.0.190'}

Si l'id du bridge est connu, il est possible de le spécifier au processeur MBIO avec l'attribut
"id". Cela provoquera un scan automatique du réseau pour déterminer son adresse ip

        <Hue name='myhue' id='ecb5fafffe9ac5c5' refresh='60' >
            ...
        </Hue>

L'adresse ip du bridge est sauvegardée dans un fichier de configuration local (bridge.myhue.dat), ce
qui permet d'éviter la phase du scan réseau si l'adresse ip idu bridge n'a pas changé. Dans la phase
de démarrage, le processeur MBIO effectue une authentification avec le bridge pour obtenir un token
qui sera sauvegardé dans un fichier local (token.myhue.dat). Le processus d'authentification exige
que le bouton du bridge soit pressé pour pouvoir obtenir un token.

Le processeur MBIO gère les notions de "room" (regroupement de devices), "zone" (regroupement de
rooms+devices) et de "device". Le processeur intègre des fonctions qui permettent de "scanner" un
bridge

    >>> task=mbio.tasks('hue')
    >>> task.hue.rooms.dump()
    +----------+--------------------------------------+---------------+------------------+
    | TYPE     | id                                   | ...           | name             |
    +----------+--------------------------------------+---------------+------------------+
    | HueRooms | 0c9acd47-525a-4cc5-a1eb-a0998fe1040a | /groups/85    | cuisine          |
    | HueRooms | 14a32837-94bb-4179-b8a2-d36dc607ef77 | /groups/92    | salle de conf    |
    | HueRooms | 460f8e79-e125-4321-ba3b-cb888611a587 | /groups/83    | sav              |

    >>> task.hue.zones.dump()
    +----------+--------------------------------------+---------------+----------+
    | TYPE     | id                                   | ...           | name     |
    +----------+--------------------------------------+---------------+----------+
    | HueZones | 36f15177-af2e-4105-a87e-25f27ae41e35 | /groups/91    | alarme   |


On déclare une room avec la balise "room" et l'attribut "id"

    <Hue bridge='' id='ecb5fafffe9ac5c5' refresh='60' >¬

        <Room id='0c9acd47-525a-4cc5-a1eb-a0998fe1040a' name='cuisine' dimmable='True' />¬

    </Hue>

ce qui aura pour effet de créer les variables MBIO suivantes

   MBIOTaskHue(hue, RUN)
   ├── MBIOValueDigital(myhue_comerr=OFF, 8s, #39)
       ...
   ├── MBIOValueDigitalWritable(myhue_cuisine_state=OFF, flags=[CW!], 10s, #39)
   ├── MBIOValueWritable(myhue_cuisine_level=0%, flags=[W!], 10s, #39)

La variable state permet de monitorer/piloter l'état ON/OFF de l'éclairage de la "room". Si
l'attribut "dimmable" est déclaré comme "True" (False par défaut), la variable "level" permet de
monitorer/piloter l'intensité (0-100%) de l'éclairage de la "room". La variable level n'est créée
que si l'attribut dimmable est True.

Une zone est déclarée d'une manière similaire et produira les mêmes variables qu'une zone
 
    <Zone id='36f15177-af2e-4105-a87e-25f27ae41e35' name='alarm' dimmable='False' />¬

le processeur MBIO peut gérer des devices. Actuellement, les devices suivants sont intégrables

    Détecteur de mouvement
    <IR id='84e415ee-62ff-4b74-96eb-06579e3052e0' name='ir3' comment='irentree' />¬
    MBIOValueDigital(myhue_ir3_motion=ON, flags=[C], 2s, #8)

Lorsque le processeur MBIO ne parvient pas à dialoguer avec le bridge, les variables correspondantes
sont mise en erreur. Une variable "comerr" indique s'il y a une erreur de communication active avec
ile bridge.


Données MeteoSuisse
===================

Le processeur MBIO peut se synchroniser sur les données 10min fournies par MeteoSuisse.

    <Config>
        ...
        <MeteoSuisse name='weather'>
            <Station name='GVE' />
        </MeteoSuisse>
        ...
    </Config>

La liste des stations météo disponibles est la suivante, toutes les stations ne fournissant pas
forcément toutes les mesures possibles :

    TAE   Aadorf / Tänikon
    COM   Acquarossa / Comprovasco
    ABO   Adelboden
    AIG   Aigle
    ALT   Altdorf
    ARH   Altenrhein
    AND   Andeer
    ANT   Andermatt
    ARO   Arosa
    RAG   Bad Ragaz
    BAN   Bantiger
    BAS   Basel / Binningen
    LAT   Bergün / Latsch
    BER   Bern / Zollikofen
    BEZ   Beznau
    BIA   Biasca
    BIN   Binn
    BIZ   Bischofszell / Sitterdorf
    BIV   Bivio
    BIE   Bière
    BLA   Blatten, Lötschental
    BOL   Boltigen
    BOU   Bouveret
    BUS   Buchs / Aarau
    BUF   Buffalora
    FRE   Bullet / La Frétaz
    CEV   Cevio
    CHZ   Cham
    CHA   Chasseral
    CHM   Chaumont
    CHU   Chur
    CHD   Château-d'Oex
    CIM   Cimetta
    CDM   Col des Mosses
    GSB   Col du Grand St-Bernard
    COY   Courtelary
    CMA   Crap Masegn
    CRM   Cressier
    DAV   Davos
    DEM   Delémont
    DIS   Disentis
    EBK   Ebnat-Kappel
    EGH   Eggishorn
    EGO   Egolzwil
    EIN   Einsiedeln
    ELM   Elm
    ENG   Engelberg
    EVI   Evionnaz
    EVO   Evolène / Villa
    FAH   Fahy
    FLU   Flühli, LU
    GRA   Fribourg / Grangeneuve
    FRU   Frutigen
    GVE   Genève / Cointrin
    GES   Gersau
    GIH   Giswil
    GLA   Glarus
    GOR   Gornergrat
    GRE   Grenchen
    GRH   Grimsel Hospiz
    GRO   Grono
    GRC   Grächen
    GOS   Göschenen
    GOE   Gösgen
    GUE   Gütsch, Andermatt
    GUT   Güttingen
    HLL   Hallau
    HOE   Hörnli
    ILZ   Ilanz
    INT   Interlaken
    JUN   Jungfraujoch
    KOP   Koppigen
    BRL   La Brévine
    CDF   La Chaux-de-Fonds
    DOL   La Dôle
    LAC   Lachen / Galgenen
    LAG   Langnau i.E.
    MLS   Le Moléson
    LEI   Leibstadt
    ATT   Les Attelas
    CHB   Les Charbonnières
    DIA   Les Diablerets
    MAR   Les Marécottes
    OTL   Locarno / Monti
    LUG   Lugano
    LUZ   Luzern
    LAE   Lägern
    MAG   Magadino / Cadenazzo
    MAS   Marsens
    MAH   Mathod
    MTR   Matro
    MER   Meiringen
    MOB   Montagnier, Bagnes
    MVE   Montana
    GEN   Monte Generoso
    MOA   Mosen
    MTE   Mottec
    MOE   Möhlin
    MUB   Mühleberg
    NAS   Naluns / Schlivera
    NAP   Napf
    NEU   Neuchâtel
    CGI   Nyon / Changins
    OBR   Oberriet / Kriessern
    ORO   Oron
    BEH   Passo del Bernina
    PAY   Payerne
    PFA   Pfäffikon, ZH
    PIL   Pilatus
    PIO   Piotta
    COV   Piz Corvatsch
    PMA   Piz Martegnas
    PLF   Plaffeien
    ROB   Poschiavo / Robbia
    PUY   Pully
    ROE   Robièi
    RUE   Rünenberg
    SBE   S. Bernardino
    HAI   Salen-Reutenen
    SAM   Samedan
    SAG   Sattel, SZ
    SHA   Schaffhausen
    SRS   Schiers
    SPF   Schüpfheim
    SCU   Scuol
    SIA   Segl-Maria
    SIM   Simplon-Dorf
    SIO   Sion
    STC   St. Chrischona
    STG   St. Gallen
    SMM   Sta. Maria, Val Müstair
    SBO   Stabio
    SAE   Säntis
    THU   Thun
    TIT   Titlis
    UEB   Uetliberg
    ULR   Ulrichen
    VAD   Vaduz
    VAB   Valbella
    VLS   Vals
    VEV   Vevey / Corseaux
    VIO   Vicosoprano
    VIT   Villars-Tiercelin
    VIS   Visp
    WFJ   Weissfluhjoch
    WYN   Wynau
    WAE   Wädenswil
    PSI   Würenlingen / PSI
    ZER   Zermatt
    REH   Zürich / Affoltern
    SMA   Zürich / Fluntern
    KLO   Zürich / Kloten

La déclaration d'une station météo va implicitement créer les variables suivantes

    t      Température ide l'air à 2m du sol (dernière mesure)
    r      rayonnement global (moyenne sur 10min)
    hr     humidité relative de l'air (moyenne sur 10min)
    dewp   point de rosée à 2m du sol (dernière mesure)
    wind   vitesse du vent (moyenne sur 10min)
    rain   hauteur des précipitations (sur 10 min)

    MBIOTaskMeteoSuisse(weather, RUN)
    ├── MBIOValue(weather_gve_t=6.6C, 8s, #1)
    ├── MBIOValue(weather_gve_hr=83.4%, 8s, #1)
    ├── MBIOValue(weather_gve_r=0.0W/m2, 8s, #1)
    ├── MBIOValue(weather_gve_dewp=9.3C, 8s, #1)
    ├── MBIOValue(weather_gve_wind=7.388888888888889ms, 8s, #1)
    ├── MBIOValue(weather_gve_rain=0.1mm, 34s, #2)
    └── MBIOValueDigital(weather_comerr=False, 8s, #1)

La variable "comerr" indique s'il y a une erreur de communication active avec les webservices
MeteoSuisse (service non atteignable).


Danfoss Ally
============

Le processeur MBIO peut s'interfacer avec les systèmes Danfoss Ally. L'API cloud Danfoss est utilisé
(https://developer.danfoss.com/user/login). Il faut déclarer une "app" sur son compte Danfoss, et
fournir les jetons d'authentification "key" et "secret" de l'application au processeur MBIO, en
s'assurant que l'application aie bien accès à l'API "Ally". Le processeur aura accès à l'ensemble
des systèmes Ally accessibles par ce compte.

    <Config>
        ...
        <Ally name='myally' key='xxx' secret='yyy' refresh='60'>
            ...
        </Ally>
        ...
    </Config>

L'attribut 'refresh' permet de définir la période de rafraichissement automatique des données
Danfoss (par défaut 60s) par le processeur MBIO.

    Attention : le fichier de configuration XML étant automatiquement "lowerisé" avant
    interprétation, les attributs "key" et "secret" ne peuvent pas contenir des caractères 
    majuscules.  Ces champs doivent donc être donnés encodés au format "b16" (www.hexator.com).

La tâche Ally propose une méthode ".b16encode(str)" qui permet de convertir aisément une chaine au
format b16

    >>> task=mbio.task('myally')
    >>> task.b16encode('helloWorld!')
    '(b16)68656C6C6F576F726C6421'

Les données d'authentification sont automatiquement sauvegardées dans les fichiers de données
persistentes liés à la tâche (key.myally.dat et secret.myally.dat, "myally" étant le "name" de
l'instance de la tâche "Ally"). Ces fichiers font partie du backup automatique réalisé par la CPU.
Il est donc possible de sortir les données d'authentification du fichier de configuration MBIO. A
noter que l'authentification peut manuellement être réalisée à partir de la tâche nommée "ally"

    >>> task.auth('key', 'secret')

Les données d'authentification fournies (key, secret) sont immédiatement sauvegardées et un jeton
d'authentification est automatiquement regénéré avec l'API Danfoss. Il est donc possible de
"démarrer" sans authentification et de réaliser l'authentification "online" (la première fois).

Chaque device est identifié par son "id" Danfoss (disponible depuis l'application Danfoss) et nommé
dans le processeur MBIO par un nom (qui doit être unique sur l'ensemble des devices Ally) par
l'attribut "name".

Les devices suivants sont supportés par le processeur MBIO

  a) Vanne motorisée pour radiateur Ally
 
        <Ally name='myally'>
            <Radiator id='xxx' name='radiateur1' />
        </Ally>

        MBIOTaskDanfossmyally(myally, RUN)
        ├── MBIOValueDigital(myally_comerr=OFF, 0s, #0)
        ├── ...
        ├── MBIOValue(myally_radiateur1_t=21.5C, 0s, #0)
        ├── MBIOValueWritable(myally_radiateur1_sp=21.0C, flags=[W!], 0s, #0)
        ├── MBIOValue(myally_radiateur1_bat=88%, 0s, #0)
        ├── MBIOValueDigital(myally_radiateur1_heat=ON, 0s, #0)
        └── MBIOValueDigital(myally_radiateur1_err=OFF, 0s, #0)

     La variable 't' fourni la température ambiante de référence utilisée par la vanne.
     La variable 'sp' fourni la consigne de température utilisée par la vanne (writable).
     La variable 'bat' fourni l'état de la batterie du servo-moteur de vanne.
     La variable 'heat' fourni l'état d'ouverture de la vanne.
     La variable 'err' indique s'il y a une erreur active avec ce device.

  b) Sonde de température+hygrométrie Ally

        <Ally name='myally'>
            <Sensor id='xxx' name='sonde1' />
        </Ally>

        MBIOTaskDanfossmyally(myally, RUN)
        ├── MBIOValueDigital(myally_comerr=OFF, 0s, #0)
        ├── ...
        ├── MBIOValue(myally_sonde1_t=22.2C, 0s, #0)
        ├── MBIOValue(myally_sonde1_hr=36%, 0s, #0)
        └── MBIOValue(myally_sonde1_bat=56%, 0s, #0)

     La variable 't' fourni la mesure de la température ambiante.
     La variable 'hr' fourni la mesure de l'hygrométrie.
     La variable 'bat' fourni l'état de la batterie de la sonde.
     La variable 'err' indique s'il y a une erreur active avec ce device.

  c) Thermostat de contrôle d'une zone de chauffage de sol "Icon2"

        <Ally name='myally'>
            <Sensor id='xxx' name='zone1' />
        </Ally>

        MBIOTaskDanfossmyally(myally, RUN)
        ├── MBIOValueDigital(myally_comerr=OFF, 0s, #0)
        ├── ...
        ├── MBIOValue(myally_zone1_t=22.0C, 0s, #0)
        ├── MBIOValueWritable(myally_zone1_sp=22.0C, flags=[W!], 0s, #0)
        ├── MBIOValue(myally_zone1_bat=85%, 0s, #0)
        ├── MBIOValueDigital(myally_zone1_heat=OFF, 0s, #0)
        └── MBIOValueDigital(myally_zone1_err=OFF, 0s, #0)

     La variable 't' fourni la température ambiante de référence utilisée par le thermostat.
     La variable 'sp' fourni la consigne de température utilisée par le thermostat (writable).
     La variable 'bat' fourni l'état de la batterie du thermostat.
     La variable 'heat' fourni l'état de commande du thermostat (=signal de commande des vannes).
     La variable 'err' indique s'il y a une erreur active avec ce device.

A noter que l'id d'un device est des la forme "bfad9453a016b0be2bwvt1". L'id d'un device est
disponible dans l'application Danfoss Ally (Settings->Informations de l'appareil).

La variable "comerr" indique s'il y a au moins un device en erreur (myally_comerr dans l'exemple
ci-dessus).

Il convient de se rappeler que la longueur maximum d'un nom de variable MBIO ne doit pas dépasser 32
caractères (limitation côté CPU). Dès lors, le choix des attributs "names" (nom de la tâche Ally,
nom des devices) doit être choisi "au plus court". Il ne doit pas y avoir de recoupement entre le
nom des différents devices déclarés (même entre plusieurs types de devices).

Au démarrage, la tâche Ally va demander à l'API la liste complète des devices disponibles (rendus
accessibles via l'authentification spécifiée). Cela permet de demander à la tâche Ally une
proposition de configuration XML à compléter/modifier selon besoins, réduisant ainsi à quasi "néant"
le travail de déclaration des devices Ally dans le processeur MBIO :

    >>> task.buildConfig()

    <Ally name='myally' refresh='60' key='(b16)6676...' secret='(b16)63395...'>
        <Radiator name='' id='bfbf...' comment='Danfoss Ally™ Radiator Thermostat Sdb 2eme' />
        <Sensor name='' id='bfea...' comment='Danfoss Ally™ Room Sensor 9+10 chambre master' />
        <Icon2 name='' id='bfb5...' comment='Danfoss Icon2 RT 3+4' />
    </Ally>


Tâches Google Sheet (GSheet)
============================

Le processeur MBIO peut synchroniser des données avec des feuilles de calcul Google Sheets. Cette
fonctionnalité permet d'utiliser une feuille de calcul comme interface de supervision simplifiée,
comme outil d'historisation, ou comme source de configuration externe. Chaque balise "gsheet" crée
une tâche dédiée avec ses propres accès.

    <Config>
        ...
        <GSheet name='gs' credentials='digimat-mbio-gapi.json' refresh='60' timeout='10' id='...'>
            ...
        </GSheet>
        ...
    </Config>

L'attribut "credentials" pointe vers le fichier JSON de compte de service Google (par défaut
"digimat-mbio-gapi.json") qui doit se trouver dans le répertoire racine ou dans
/etc/sysconfig/digimat/credentials. L'attribut "id" est l'identifiant unique de la feuille Google
Sheet (disponible dans l'URL de la feuille). L'attribut "refresh" définit la période de lecture (en
secondes) des cellules configurées.

La configuration se fait par feuille (onglet), déclarée par la balise "sheet".

    <GSheet ...>
        <Sheet name='Feuille1' alias='main'>
            ...
        </Sheet>
    </GSheet>

L'attribut "name" doit correspondre exactement au nom de l'onglet dans Google Sheet. L'attribut
"alias" (optionnel) permet de définir un préfixe pour les variables MBIO générées.

Déclaration des variables (Mapping Cellule <-> Variable)
--------------------------------------------------------

Les cellules peuvent être mappées vers des variables MBIO de type Analog Input (AI), Digital Input
(DI), Analog Output (AO) ou Digital Output (DO). Une cellule est identifiée par son adresse (ex:
"B4") ou par une plage nommée (Named Range).

    <Sheet name='Data'>
        <AI name='temp_ext' cell='B2' unit='C' />
        <DI name='alarm_gen' cell='Status!C5' />
        <AO name='consigne' cell='Settings!B10' />
    </Sheet>

Ces déclarations créent des variables MBIO (ex: gs_main_temp_ext).

- AI/DI (Lecture seule) : La valeur est lue dans la Sheet et mise à jour dans MBIO.
- AO/DO (Lecture/Écriture) : La valeur est lue périodiquement. Si la variable MBIO est modifiée
  (écriture), la nouvelle valeur est envoyée vers la Sheet.

L'attribut "retain" (par défaut True pour AI/DI) permet de conserver la dernière valeur connue au
redémarrage. Pour les AO/DO, l'attribut "storeunit" permet d'écrire l'unité dans la cellule
adjacente lors de l'export.

Fonctionnalités avancées (Import/Export/Dump)
---------------------------------------------

Outre le mapping direct, la tâche GSheet offre des fonctions de transfert en masse.

a) Import (Sheet -> MBIO)

Permet de forcer la valeur d'une variable MBIO existante (n'importe laquelle dans le processeur) à
partir d'une cellule.

    <Import key='gw1_4_do1' cell='B10' />

b) Export (MBIO -> Sheet)

Permet d'écrire la valeur d'une variable MBIO vers une cellule.

    <Export key='gw1_4_ai0' cell='C12' storeunit='true' />

c) Dump (MBIO -> Sheet en liste)

Permet de "dumper" une liste de variables (filtre par clé) vers une zone de la feuille. Cela écrit
la clé, le tag, la valeur, l'unité et les flags sur des colonnes consécutives.

    <Dump key='gw1_*' cell='A20' refresh='300' />

Cela permet de créer facilement des tableaux de bord d'état complets dans Google Sheet.


Serveur BACnet/IP
=================

Le processeur MBIO peut exposer ses variables sur un réseau BACnet/IP via un serveur intégré
(bacpypes3). La tâche BACnet est déclarée par la balise "bacnet". L'attribut "name" permet de nommer
la tâche (et donc le préfixe des variables internes de la tâche). L'attribut "deviceid" définit
l'identifiant BACnet unique du device (obligatoire, doit être unique sur le réseau BACnet).
L'attribut "interface" définit l'adresse IP source du serveur (au format CIDR, ex: '192.168.0.10/24').
L'attribut "port" définit le port UDP BACnet (par défaut 47808).

    <Config>
        ...
        <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24' port='47808'>
            ...
        </Bacnet>
        ...
    </Config>

Si l'interface n'est pas précisée, le serveur utilisera l'interface réseau du processeur MBIO.
Attention : l'adresse IP doit être spécifiée au format CIDR avec le masque de sous-réseau
(ex: '192.168.0.10/24'). Si le masque est omis, /24 est ajouté automatiquement. L'attribut "bindall"
(False par défaut) permet de lier le serveur à toutes les interfaces réseau disponibles
(utile pour les environnements multi-réseau ou le debug).

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24' bindall='false'>
        ...
    </Bacnet>

Le serveur BACnet supporte l'enregistrement auprès d'un BBMD (BACnet Broadcast Management Device)
pour le routage des broadcasts BACnet entre sous-réseaux. L'attribut "bbmd" permet de définir
l'adresse IP du BBMD

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24' bbmd='192.168.0.1'>
        ...
    </Bacnet>


Contrôle d'accès en écriture
-----------------------------

L'attribut "writeacl" permet de restreindre les écritures BACnet aux seuls réseaux IP autorisés
(les lectures ne sont pas affectées). Les réseaux sont spécifiés au format CIDR, séparés par des
virgules. Si l'attribut n'est pas défini, toutes les écritures sont autorisées.

    <Bacnet name='bnet' deviceid='100' writeacl='192.168.0.0/24,10.0.1.0/24'>
        ...
    </Bacnet>


Déclaration d'objets BACnet (AV, BV)
-------------------------------------

Il est possible de déclarer des objets BACnet autonomes qui créent des variables MBIO internes à la
tâche. Ces objets sont accessibles en lecture et en écriture depuis le réseau BACnet. La valeur de
ces objets est également disponible dans le processeur MBIO sous forme de variable.

a) Analog Value (AV)

Les objets Analog Value sont déclarés avec la balise "AV". L'attribut "name" donne le nom de la
variable MBIO (préfixée par "av_"). L'attribut "unit" définit l'unité BACnet de l'objet. L'attribut
"default" permet de spécifier la valeur initiale. L'attribut "resolution" définit la résolution
de notification (par défaut 0.1).

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24'>
        <AV name='consigne_chaud' unit='C' default='22.0' resolution='0.1' />
        <AV name='consigne_froid' unit='C' default='24.0' />
    </Bacnet>

Cela produira les variables MBIO suivantes

    MBIOTaskBacnet(bnet, RUN)
    ├── MBIOValue(bnet_av_consigne_chaud=22.0C, 0s, #0)
    ├── MBIOValue(bnet_av_consigne_froid=24.0C, 0s, #0)
    └── MBIOValueDigital(bnet_comerr=False, 0s, #0)

Ces variables sont en lecture seule du point de vue MBIO (la valeur provient du réseau BACnet). Un
client BACnet peut lire et écrire la valeur de l'objet Analog Value. L'écriture depuis le réseau
BACnet met à jour la variable MBIO correspondante.

b) Binary Value (BV)

Les objets Binary Value sont déclarés avec la balise "BV". L'attribut "name" donne le nom de la
variable MBIO (préfixée par "bv_"). L'attribut "default" permet de spécifier la valeur initiale.

    <Bacnet ...>
        <BV name='mode_nuit' default='false' />
    </Bacnet>

Cela produira la variable MBIO suivante

    MBIOTaskBacnet(bnet, RUN)
    ├── MBIOValueDigital(bnet_bv_mode_nuit=False, 0s, #0)


Déclaration de programmes horaires (Schedule)
----------------------------------------------

Le serveur BACnet peut exposer des programmes horaires (ScheduleObject) modifiables depuis le réseau
BACnet par un outil de programmation (YABE, NiagaraAX, etc.). Un schedule est déclaré avec la balise
"SCH". L'attribut "name" donne le nom de la variable MBIO (préfixée par "sch_"). L'attribut "target"
définit la liste (séparée par des virgules) des noms d'objets BACnet cibles (AV ou BV déclarés dans
la même tâche). L'attribut "default" définit la valeur par défaut du programme horaire.

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24'>
        <AV name='consigne_chaud' unit='C' default='22.0' />
        <SCH name='prog_chaud' target='bnet_av_consigne_chaud' default='20.0' priority='15' />
    </Bacnet>

Cela produira les variables MBIO suivantes

    MBIOTaskBacnet(bnet, RUN)
    ├── MBIOValue(bnet_av_consigne_chaud=22.0C, 0s, #0)
    ├── MBIOValue(bnet_sch_prog_chaud=20.0, 0s, #0)
    └── MBIOValueDigital(bnet_comerr=False, 0s, #0)

La variable "sch_prog_chaud" reflète la valeur active du programme horaire (telle que calculée par le
scheduler BACnet en fonction de l'heure courante et de la programmation horaire définie). La
programmation horaire elle-même est modifiable depuis un client BACnet (weeklySchedule,
exceptionSchedule). L'attribut "priority" (par défaut 15) définit la priorité BACnet du schedule
lorsqu'il écrit dans ses objets cibles (priorityArray).

ATTENTION -- typage des schedules : le type de la valeur par défaut détermine le type du schedule et
de ses objets cibles. Ce type doit être cohérent avec les objets cibles visés :

    default='20.0'    float  (Real)    --> pilote des AV (Analog Value)
    default='5'       int    (Unsigned) --> pilote des MSV (Multi-State Value)
    default='true'    bool   (BinaryPV) --> pilote des BV (Binary Value)

Piège courant : "default='0'" (entier) au lieu de "default='0.0'" (flottant) pour piloter un AV.
Le schedule passera silencieusement en "configurationError" et sera inerte.

L'attribut "targetlocked" (True par défaut si des targets sont définis) permet d'interdire la
modification de la liste des objets cibles (listOfObjectPropertyReferences) depuis le réseau BACnet.
Le programme horaire reste modifiable, seule la liste des cibles est protégée.

    <SCH name='prog_chaud' target='bnet_av_consigne_chaud' default='20.0'
         targetlocked='true' />

Un schedule peut piloter plusieurs objets cibles simultanément (séparés par des virgules)

    <SCH name='prog_heating' target='bnet_av_sp_bureau1,bnet_av_sp_bureau2' default='21.0' />


Exposition de variables MBIO existantes
---------------------------------------

Le mécanisme le plus puissant de la tâche BACnet est la possibilité d'exposer sur le réseau BACnet
des variables MBIO provenant d'autres gateways, devices ou tâches du processeur. La balise "expose"
permet de sélectionner les variables MBIO à exposer (par nom, avec wildcards).

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24'>
        <Expose name='gw1*' instance='100000' />
        <Expose name='weather*' instance='200000' />
    </Bacnet>

L'attribut "name" est un filtre de sélection (supporte les wildcards *, identique aux filtres
Notifiers). L'attribut "instance" (par défaut 100000) définit le numéro d'instance de départ pour les
objets BACnet créés. Chaque variable MBIO sélectionnée est automatiquement exposée comme un objet
BACnet du type approprié (AV pour les analogiques, BV pour les digitales). L'unité BACnet est
automatiquement déterminée à partir de l'unité de la variable MBIO (mapping interne des unités
Digimat vers les unités BACnet standard). Les variables exposées sont en lecture seule depuis le
réseau BACnet (la valeur provient du device/de la tâche MBIO d'origine).

Attention : les variables internes à la tâche BACnet (AV, BV, SCH) ne sont pas exposées une seconde
fois par les filtres "expose". Seules les variables provenant d'autres tâches ou gateways sont
concernées.

Plusieurs balises "expose" peuvent être utilisées pour exposer des ensembles de variables différents
avec des plages d'instances distinctes. L'état d'erreur de chaque variable MBIO est automatiquement
propagé vers l'objet BACnet correspondant (reliability, outOfService).


Persistence
-----------

Les données du serveur BACnet (état des schedules, programmation horaire, mapping des identifiants
d'instances) sont automatiquement persistées sur disque. Au redémarrage, les programmes horaires et
les identifiants d'instances sont restaurés. Cela garantit que les identifiants BACnet restent
stables entre les redémarrages du processeur MBIO (un objet conserve son objectIdentifier). La
persistence du numéro d'instance pour une variable (définie par son nom) permet de s'assurer qu'elle
sera toujours représentée par la même instance BACnet (par exemple AV100017) même si l'ordre de
déclaration des variables diffère au moment du démarrage du processeur MBIO.

Les identifiants d'objets temporairement non déclarés sont conservés pendant 30 jours pour éviter la
réassignation. Au-delà, l'identifiant est libéré.

Toute la persistence est stockée dans le fichier local "server.persistentdata.bnet.dat" (pour la tâche
nommée "bnet").


Variables systèmes
------------------

    -- bnet_comerr
    True si le serveur BACnet n'est pas opérationnel (erreur de démarrage, crash du thread BACnet)

    -- bnet_exposedcount
    Contient le nombre de variables MBIO "exposées" par les directives "Expose"


Exemple de configuration complète
----------------------------------

    <Bacnet name='bnet' deviceid='100' interface='192.168.0.10/24'
            bbmd='192.168.0.1' writeacl='192.168.0.0/24'>

        <!-- Objets BACnet autonomes (R/W depuis le réseau) -->
        <AV name='sp_chaud' unit='C' default='22.0' resolution='0.1' />
        <AV name='sp_froid' unit='C' default='24.0' resolution='0.1' />
        <BV name='mode_nuit' default='false' />

        <!-- Programmes horaires -->
        <SCH name='prog_chaud' target='bnet_av_sp_chaud' default='20.0'
             label='Programme chauffage' priority='15' />
        <SCH name='prog_froid' target='bnet_av_sp_froid' default='26.0'
             label='Programme refroidissement' />
        <SCH name='prog_nuit' target='bnet_bv_mode_nuit' default='false'
             label='Mode nuit' />

        <!-- Exposition de variables MBIO existantes -->
        <Expose name='gw1*' instance='100000' />
        <Expose name='weather*' instance='200000' />
    </Bacnet>


Système KNX
===========

Le processeur MBIO peut s'interfacer avec une installation KNX via un routeur/interface IP KNX
(tunneling). La tâche KNX est déclarée par la balise "knx".

    <Config>
        ...
        <Knx name='knx' host='192.168.0.10' refresh='10'>
            ...
        </Knx>
        ...
    </Config>

L'attribut "host" définit l'adresse IP du routeur KNX.

Déclaration des groupes
-----------------------

Les objets de communication sont déclarés par des groupes ("group"). Chaque groupe associe une
adresse de groupe KNX (ex: '1/0/1') à une variable MBIO.

    <Knx ...>
        <Group name='salon_light' address='1/0/1' type='bool' writable='true' />
        <Group name='salon_temp' address='2/1/0' type='float' />
    </Knx>

L'attribut "type" définit le format de données DPT (bool, byte, int, float, number).
Si "writable" est vrai, la variable MBIO sera modifiable et toute écriture déclenchera l'envoi d'un
télégramme KNX vers le groupe.

La configuration ci-dessus produira les variables suivantes :

    MBIOTaskKnx(knx, RUN)
    ├── MBIOValueDigitalWritable(knx_salon_light_state=False)
    ├── MBIOValue(knx_salon_temp_value=21.5)
    └── MBIOValueDigital(knx_comerr=False)

La variable "comerr" indique l'état de la connexion avec le routeur KNX.


Tâche Pinger (Surveillance réseau)
==================================

La tâche Pinger permet de surveiller la présence d'équipements sur le réseau via des requêtes ICMP
(Ping). Cela permet de créer des variables d'état (ON/OFF) basées sur la réponse au ping.

    <Config>
        ...
        <Pinger name='ping' period='15' timeout='60'>
            <Host name='server' ip='192.168.0.1' />
            <Host name='camera' ip='192.168.0.50' timeout='10' />
        </Pinger>
        ...
    </Config>

L'attribut "period" définit la fréquence des pings (en secondes). L'attribut "timeout" définit le
temps après lequel l'hôte est considéré comme "Down" (OFF) s'il ne répond pas. Ce timeout peut être
défini globalement ou par hôte.

Cette configuration produira :

    MBIOTaskPinger(ping, RUN)
    ├── MBIOValueDigital(ping_server=True)  (Répond au ping)
    ├── MBIOValueDigital(ping_camera=False) (Ne répond pas)
    └── MBIOValueDigital(ping_comerr=False) (True si au moins un hôte est down)


A VENIR ?
=========

Système d'IRC ou de PROCESSUS virtuels : le processeur MBIO supporte des TASK configurables, comme
par exemple un IRC virtuel qui expose ses propres variables (genre spHeating, spCooling, ...). On
spécifie les entrées utiles par le nom des variables MBIO disponibles (par exemple tamb=gw1_20_t si
elle vient d'une sonde Belimo) et on lie les sorties virtuelles sur des variables MBIO (par exemple
des sorties analogiques pour les vannes chaud/froid).


UPDATES
=======

20250222/1.0.114
-- Support Danfoss Ally
-- Support Sonde Sensortec EL-D

20250207/1.0.108
-- Sonde Belimo : gestion de la vitesse ventilateur au format entier (et plus 0..100%)

20250114/1.0.105
-- Sonde Belimo : support correct du point de consigne en mode relatif
-- Sonde Belimo : gestion correcte des registres en mode int16 pour les nombres négatifs
-- Augmentation du délai RESYNC des devices de 60s à 180s
