Это старая версия документа!
Данная статья формируется в процессе написания кода
Далее описана функциональность драйвера Modbus v2
LightHub можно настроить на работу в качестве шлюза с фактически любым устройством, поддерживающим Modbus RTU и работающем в режиме Slave
В отличии от v1, драйвер можно настроить на работу в качестве шлюза с фактически любым устройством, поддерживающим Modbus RTU и работающем в режиме Slave Поддерживается как чтение так и запись в modbus устройства
В корневом разделе modbus конфигурации описывается библиотека используемых типов устройств.
Для каждого устройства в библиотеки возможно задать такие параметры как скорость обмена (раздел baud) /параметры четности (раздел serial), назначение и тип регистров (раздел par), а также, интервал и параметры опроса этих регистров (раздел poll)
Данный раздел содержит информацию о назначении каждого опрашиваемого или управляемого регистра (или групп регистров) используемого устройства. Раздел состоит из JSON объектов следующего формата:
"t_heat":{"reg":8,"map":[0,1024,0,1024],"type":"i16"},
В примере выше:
Возможные варианты типов:
задает интервал и параметры опроса регистров устройства
Причем, в целях оптимизации обмена, можно опрашивать устройство командой чтения группы регистров. Пример:
"poll":{"regs":[[40000,40014],[30000,30002],40099],"delay":10000}
Обозначает, что с интервалом 10 сек будут произведены следующие три опроса:
Для каждого из успешно прочитанных регистров, проводится поиск соответствия в разделе par и ir Если есть запись, соответствующая данному регистру, прочитанные значения преобразовываются (см описание map) и направляются в MQTT и/или локальным объектам контроллера
Отправка происходит, если с момента последнего опроса значение регистра изменилось
Пример:
"baud":9600,
"serial":"8E1"
Соответственно, скорость обмена (по умолчанию, 9600) и параметр четности порта Параметр четности - одно из значений ниже. По умолчанию 8N1
«8E1»,»8N1«,»8E2«, «8N2», «8O1», «8O2», «8M1», «8S1», «7E1», «7N1», «7E2», «7N2», «7O1», «7O2», «7M1», «7S1»
В данном разделе задаются конкретные modbus устройства по шаблону, определенному в разделе modbus
"items": {
"dimer1":[14,[1,
"dim4",
{
"ch1":{"emit":"aaa1,"item":"localdimmer1"},
"ch2":{"emit":"abc/aaa2"},
"ch3":{"item":"localdimmer3"},
"ch4":[{"emit":"aaa4,"item":"localdimmer4"},{"emit":"aaa44,"item":"localdimmer44"}]
}
]
],
В данном примере, создается item (объект) dimer1 с типом 14 (modbus v2) адресом modbus=1, на основе библиотечного устройства «dim4»
Устройство опрашивается согласно настройкам в библиотеке. А вот результаты опроса используются согласно настройкам в items. В данном примере,
Строки ch1 - ch4 в данном примере, определенные в третем параметре массива конфигурации, далее будем называть «именованными параметрами modbus item»
Имена этих параметров используются для доступа на запись в modbus Для данного примера, чтобы записать значение в первый канал modbus димера можно использовать mqtt топик:
myhome/in/dimer1/ch1/set
(Здесь и далее для простоты предполагаем что mqtt префикс по-умолчанию myhome и обращение через broadcast имя устройства in)
«ch1» используется как subItem устройства (ставится между именем item и суффиксом)
таким образом обеспечивается индивидуальный доступ к каждому описанному в настройках регистру modbus устройства из mqtt/httpApi
NB. Не надо именовать данные параметры именами стандартных суффиксов (set, cmd, fan и пр) (см. полный перечень стандартных суффиксов)
Также, возможно управлять не отдельными subItem - ами modbus устройства, а устройством в целом, по аналогии с тем, как это делается для всех типичных item-ов LightHub. То есть, задавать один общий параметр устройства через суффикс /set, команды через суффикс /cmd и пр (см. полный перечень стандартных суффиксов)
Для этого в разделе шаблона устройства, в описании конкретного параметра modbus можно задать связь параметра с конкретным суффиксом при помощи значения «id»=N, где N - цифровой идентификатор стандартного суффикса (см. полный перечень стандартных суффиксов)
Далее, соберем фрагменты в более полный пример:
"modbus":
{
"airset":{
"baud":9600,
"serial":"8N1",
"poll":{"regs":[1,[8,24]],"delay":1000},
"par":{
"t_heat":{"reg":8,"map":[0,1024,0,1024],"type":"i16"},
"mode":{"reg":24}
}
},
"dim4":{
"poll":{"regs":[[0,4]],"delay":10000},
"par":{
"ch1":{"reg":0},
"ch2":{"reg":1},
"ch3":{"reg":2},
"ch4":{"reg":3}
}
},
"sensair":{"baud":9600,
"poll":{"irs":[[0,3],21,[25,30]],"regs":[0,1,31],"delay":1000},
"par":{
"co2":{"ir":3},
"meterStat":{"ir":0},
"alarmStat":{"ir":1},
"outStat":{"ir":0},
"pwm":{"ir":21},
"typeid":{"ir":25,"type":"u32"},
"mapver":{"ir":27},
"fwver":{"ir":28},
"sensorid":{"ir":29,"type":"u32"},
"ack":{"reg":0},
"command":{"reg":1},
"abc":{"reg":31}
}
}
},
"panel":{
"poll":{"regs":[[40000,40014],[30000,30002]],"delay":10000},
"par":{
"fan" :{"reg":40000},
"mode" :{"reg":40001},
"set" :{"reg":40002},
"pwr" :{"reg":40003},
"alm01":{"reg":40004},
"alm17":{"reg":40005},
"alm33":{"reg":40006},
"sethum" :{"reg":40007},
"setvoc" :{"reg":40008},
"temp" :{"reg":30000},
"hum" :{"reg":30001},
"voc" :{"reg":30002},
"ch_temp" :{"reg":40009},
"ext_temp" :{"reg":40010},
"out_temp" :{"reg":40011},
"water_temp" :{"reg":40012},
"ch_hum" :{"reg":40013},
"heat_pwr":{"reg":40014}
}
}
},
"items": {
"airset1":[14,[10,"airset",{"t_heat":{"emit":"aaa"}}]],
"panel1":[14,[2,"panel"]],
"dimer1":[14,[1,"dim4",
{
"ch1":{"emit":"aaa1,"item":"localdimmer1"},
"ch2":{"emit":"abc/aaa2"},
"ch3":{"item":"localdimmer3"},
"ch4":[{"emit":"aaa4,"item":"localdimmer4"},{"emit":"aaa44,"item":"localdimmer44"}]
}
]
]
},
"sensair1":[14,[254,
"sensair",
{"co2":{"emit":"co2"}}
]
]
}
}
В процессе опроса устройств, драйвер запоминает последнее считанное из регистра modbus значение во внутреннюю переменную @S внутри именованного параметра item
Если значение не изменилось с последнего считывания - операция по отправки значения в modbus или локальному обьекту не производится
Данное поведение можно отменить. Если данную переменную определить в конфиге и ее тип будет отличен от целого значения, последнее опрошенное значение не будет сохраняться, что приведет к отправке результата каждого опроса в mqtt или локальному обьекту
Пример - панель управления климатом Zentec. Измерения влажности передаются каждый раз:
"modbus":
{
"panel":{
"serial":"8E1",
"poll":{"regs":[[40000,40014],[30000,30002]],"delay":10000},
"par":{
"fan" :{"reg":40000,"map":[1,[0,7,0,100]],"id":11},
"mode" :{"reg":40001,"mapcmd":[2,[[1,"FAN_ONLY"],[2,"HEAT"],[4,"COOL"],[8,"AUTO"]]]},
"settemp" :{"reg":40002,"id":12},
"pwr" :{"reg":40003,"mapcmd":[2,[[0,2],[1,1]]]},
"alm01":{"reg":40004},
"alm17":{"reg":40005},
"alm33":{"reg":40006},
"sethum" :{"reg":40007,"id":13},
"setvoc" :{"reg":40008,"id":14},
"roomtemp" :{"reg":30000,"type":"x10"},
"hum" :{"reg":30001},
"voc" :{"reg":30002},
"ch_temp" :{"reg":40009,"type":"x10","id":15},
"ext_temp" :{"reg":40010,"type":"x10","id":16},
"out_temp" :{"reg":40011,"type":"x10","id":17},
"water_temp" :{"reg":40012,"type":"x10","id":18},
"ch_hum" :{"reg":40013},
"heat_pwr":{"reg":40014}
}
}
},
items:{
"p_zal3":[14,[2,"panel",
{
"fan" :{"emit":"edem/air/vents/zal3/fan"},
"mode":{"emit":"edem/air/vents/zal3/mode"},
"pwr" :{"emit":"edem/air/vents/zal3/pwr"},
"sethum":{"emit":"edem/air/humzal3/set"},
"hum" :{"emit":"edem/air/humzal3/val","@S":null},
"setvoc":{"emit":"edem/air/voczal3/set"},
"voc" :{"emit":"edem/air/voczal3/val"},
"settemp" :{"item":"tzal3/set"},
"roomtemp" :{"emit":"edem/fl2/term_bedr/1/val"},
"ch_temp":{},
"ch_hum":{},
"ext_temp":{},
"out_temp":{},
"water_temp":{},
"heat_pwr":{}
}
]]
}
Также, по-умолчанию, контроллер выполняет какие-то действия, только если регистр Модбас устройства поменялся не в результате записи в него со стороны контроллера(такая логика сделана, чтобы избежать зацикливания нотификаций)
Например, если в регистре число 3 а мы записали в него 5 - никаких действий при опросе не произойдет. А вот если значение в регистре изменилось в результате каких-то внутренних процессов устройства (например, пользователь изменил значение температуры на панеле) - это значение будет обработано.
Данную фильтрацию можно отменить, если в настройке параметра добавить переменную @V типа, отличного от целого. Например так:
"fan" :{"emit":"edem/air/vents/zal3/fan","@V":null},
И еще один фильтр: при попытке записать в регистр значение, не отличающееся от последнего полученного при опросе, такая попытка будет проигнорирована. Такое поведение отключить нельзя.