Добавление счетчика SDM-220 в OpenHab

от автора

Прошел почти год с момента моей первой публикации об электросчетчике с RS485/ModBus интерфейсом SDM-220, затем была вторая статья о том, как собирать с него данные и обрабатывать статистику. Это третья, надеюсь, последняя. Она о том, как интегрировать счетчик с OpenHab. Результат наконец-то меня полностью устраивает.



Итак, первая попытка собирать статистику со счетчика предпринималась с использованием внешнего облачного сервиса ThingSpeak. В качестве локального сервера, который опрашивает счетчик, использовался тонкий клиент (мини-компьютер) с установленным на флешку Ubuntu Server. Это была первая ошибка — флешка «умерла» через 3 месяца (случайность, подумал я). Не сделав никаких выводов, вторую флешку я убил за 2 месяца (закономерность). В третьей версии в качестве хранилища уже использовался usb-карман с винтом 2,5".

Сам сервис ThingSpeak позволяет производить некоторую обработку, но не дает достаточной гибкости с манипуляциями данными. Данные за сутки, например, собирались как сумма данных по часам. Если какой-то пакет данных на сервер не поступил или я отправил несколько данных во время тестирования, появлялась ошибка. Мысли о том, что придется вести двухтарифный учет с привязкой по времени суток, оптимизма не добавляли.

В общем, решил я осваивать OpenHab.

Задача первая: получить сырые данные со счетчика.

Установка самого OpenHab подробно изложена в инструкции. После установки нужно через панель Paper UI -> Bindings установить ModBus bindingbinding-modbus1 — 1.9.0

Опрос шины ModВus происходит через USB-RS485 адаптер, поэтому нужно убедиться, что адаптер есть в системе, и добавить пользователю openhab права на доступ к порту:

lsusb Bus 002 Device 002: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC  ls /dev/ttyUSB* /dev/ttyUSB0  sudo adduser openhab dialout sudo adduser openhab tty 

Затем рекомендуется настроить разрешения для Java (об этом также подробно написано в инструкции по установке OpenHab):

sudo vi /etc/default/openhab2  EXTRA_JAVA_OPTS="-Dgnu.io.rxtx.SerialPorts=/dev/ttyUSB0" 

После этих манипуляций нужно настроить конфигурационный файл services/modbus.cfg:

 sudo vi  /etc/openhab2/services/modbus.cfg  #Период опроса счетчика poll=30000  #Счетчик не позволяет вычитать все регистры за одно обращение, поэтому нужно создать отдельную запись для каждого регистра. Поле start - номер регистра. В строке connection указываем номер и параметры порта (9600,8,n,1), задержку перед чтением каждого регистра и таймаут ответа.  #напряжение - 0x00 serial.slave1.connection=/dev/ttyUSB0:9600:8:none:1:rtu:2000:1000:none:none serial.slave1.type=input serial.slave1.start=0 serial.slave1.length=2 serial.slave1.valuetype=float32  #ток - 0x06 serial.slave2.connection=/dev/ttyUSB0:9600:8:none:1:rtu:2000:1000:none:none serial.slave2.type=input serial.slave2.start=6 serial.slave2.length=2 serial.slave2.valuetype=float32  #активная мощность - 0x0C serial.slave3.connection=/dev/ttyUSB0:9600:8:none:1:rtu:2000:1000:none:none serial.slave3.type=input serial.slave3.start=12 serial.slave3.length=2 serial.slave3.valuetype=float32  #показания счетчика (активная энергия) - 0x156 serial.slave4.connection=/dev/ttyUSB0:9600:8:none:1:rtu:2000:1000:none:none serial.slave4.type=input serial.slave4.start=342 serial.slave4.length=2 serial.slave4.valuetype=float32 

Затем нужно создать элементы данных в файле items/sdm220.items:

sudo vi /etc/openhab2/items/sdm220.items  #Определяем группу для элементов Group gSDM220  #и указываем, откуда их брать и как выводить, energy - это имя иконки из стандартного набора Number sdm220_voltage  "Напряжение  [%.1f В]" <energy> (gSDM220) {modbus="slave1:0"} Number sdm220_current  "Ток  [%.2f А]" <energy> (gSDM220) {modbus="slave2:0"} Number sdm220_actpower  "Мощность  [%.1f Вт]" <energy> (gSDM220) {modbus="slave3:0"} Number sdm220_actcounter  "Счетчик электроэнергии  [%.1f кВт*ч]" <energy> (gSDM220) {modbus="slave4:0"} 

Осталось добавить текущие показания на dashboard. Для этого редактируем файл sitemaps/default.sitemap:

sudo vi /etc/openhab2/sitemaps/default.sitemap   sitemap default label="alk0v SmartHome (default sitemap)" {     Frame label="Электросчетчик" {         Text item=sdm220_voltage         Text item=sdm220_current         Text item=sdm220_actpower         Text item=sdm220_actcounter     } } 

В принципе, этого достаточно, чтобы увидеть текущие показания счетчика:

Задача вторая: настройка HabPanel и визуализация показаний

OpenHab поддерживает несколько панелей управления. Мне внешне больше всего понравилась HabPanel. Через Paper UI -> User Interfaces устанавливаем HabPanelui-habpanel — 2.0.0.

Для отрисовки графиков также нужно где-то хранить данные. OpenHab использует термин Persistence для баз данных. Мне хотелось использовать базу MySQL, в community обсуждали много проблем с этой базой, в итоге я нашел инструкцию, которая заработала и у меня.

Итак, устанавливаем MySQL Persistence (persistence-mysql — 1.9.0).

Устанавливаем MySQL

sudo apt-get install mysql-server sudo mysql -u root -p

Настраиваем базу

CREATE DATABASE OpenHAB; CREATE USER 'openhab'@'localhost' IDENTIFIED BY 'YOURPASSWORD'; GRANT ALL PRIVILEGES ON OpenHAB.* TO 'openhab'@'localhost'; quit

Рестартуем openhab

sudo service openhab2 stop sudo service openhab2 start

Правим services/mysql.cfg:

# the database url like 'jdbc:mysql://<host>:<port>/<database>' (without quotes) url=jdbc:mysql://localhost:3306/openhab  # the database user user=openhab  # the database password password=YOURPASSWORD

Правим persistence/mysql.persist. По умолчанию значения всех Items будут заноситься в базу при каждом изменении:

Strategies {         // if no strategy is specified for an item entry below, the default list will be used         everyMinute     : "0 * * * * ?"         every5Minutes : "0 */5 * * * ?"         everyHour   : "0 0 * * * ?"         everyDay    : "0 0 0 * * ?"         default = everyChange }  Items {     // persist all items once a day and on every change and restore them from the db at startup     * : strategy = default, restoreOnStartup } 

Если всё настроено правильно, в базе должна появиться таблица Items и таблицы ItemXX для каждого Item.

 mysql> use openhab; Database changed  mysql> show tables; +-------------------+ | Tables_in_openhab | +-------------------+ | Item1             | | Item2             | | Item3             | | Item4             | | Items             | +-------------------+ 5 rows in set (0.00 sec)  mysql> select * from Items; +--------+--------------------------+ | ItemId | ItemName                 | +--------+--------------------------+ |      1 | sdm220_voltage           | |      2 | sdm220_actpower          | |      3 | sdm220_actcounter        | |      4 | sdm220_current           | +--------+--------------------------+ 4 rows in set (0.00 sec) 

Теперь можно наводить красоту в HabPanel.

Добавляем Dashboard, на него добавляем новые виджеты. Для вывода значений используется виджет Dummy, для вывода графиков — Chart. Тут всё интуитивно понятно. Параметры мощности и напряжения я вывел на один график, используя две разных шкалы Y.

Указываем в качестве источника данных mysql:

Настраиваем пороги для оси напряжения:

Добавляем Items, указываем для них цвет и тип линии, для напряжения указываем ось Secondary:

Получаем результат 🙂

Задача третья: почасовый и посуточный учет затраченной электроэнергии

Отображение изменения состояния во времени — это хорошо, но хотелось еще получить статистику расхода за час, сутки, месяц. То есть задача — периодически производить некоторые вычисления. Тут на помощь приходит механизм правил в OpenHab.

Итак, настраиваем Rules.

Сначала нужно добавить новые Items в items/sdm220.items:

Number sdm220_hourcounter (gSDM220) Number sdm220_daycounter (gSDM220) 

Затем создаем файл rules/energy.rules, в котором нужно указать 2 правила: одно будет выполняться раз в час, второе — раз в сутки.

rule "Energy by hour" when         Time cron "0 0 * * * ?" then //вычисление расхода. Из текущих показаний счетчика вычитаются значения из базы на час раньше            var hour = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState(now.minusHours(1), "mysql":).state as DecimalType //вывод данных в лог для отладки         logInfo("TEST","sdm220_hourcounter = "+hour) //присваиваем значение Item         postUpdate(sdm220_hourcounter, hour) end  rule "Energy by day" when         Time cron "0 0 0 * * ?" then         var day = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState(now.minusDays(1), "mysql":).state as DecimalType         postUpdate(sdm220_daycounter, day) 

Для отладки можно использовать консоль OpenHab. Стандартные логин и пароль: openhab/habopen. Подключиться к ней можно командой:

ssh -p 8101 openhab@localhost openhab> log:tail  19:22:00.012 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.526123046875 19:22:00.014 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.861083984375 19:22:09.462 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_current changed from 16.0433025360107421875 to 5.69449329376220703125 19:22:11.500 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_actcounter changed from 2387.51904296875 to 2387.5458984375 19:22:13.532 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_voltage changed from 192.7679595947265625 to 200.4195098876953125 19:22:15.568 [INFO ] [marthome.event.ItemStateChangedEvent] - sdm220_actpower changed from 2271.8486328125 to 1132.8717041015625 19:23:00.014 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.515869140625 19:23:00.015 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.8769531250 

Или можно просматривать файл лога:

tail -f /var/log/openhab2/openhab.log 2017-04-18 19:17:45.587 [INFO ] [el.core.internal.ModelRepositoryImpl] - Refreshing model 'energy.rules' 2017-04-18 19:18:00.259 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.571044921875 2017-04-18 19:18:00.272 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.8330078125 2017-04-18 19:19:00.015 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.83789062500 2017-04-18 19:19:00.025 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.557861328125 2017-04-18 19:20:00.013 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_hourcounter_day = 0.55517578125 2017-04-18 19:20:00.024 [INFO ] [.eclipse.smarthome.model.script.TEST] - sdm220_daycounter = 10.859130859375 

Я планирую менять основной электросчетчик на двухтарифный, по которому электроэнергия, потребляемая в диапазоне с 23:00 до 07:00, оплачивается с коэффициентом 0.5, поэтому хотелось бы видеть ожидаемый эффект и вести двухтарифный учет. Сначала я просто добавил в Items и Rules дополнительные условия для времени и складывал дневные и ночные показания в две разных таблицы. В базе всё было красиво, а вот на графике выглядело коряво, так как график соединял два последних значения прямой линией:

Чтобы потешить свое чувство прекрасного, пришлось немного заморочиться.

Итак, финальный скрипт Rules для двухтарифного учета выглядит так:

rule "Energy by hour" when         Time cron "0 0 * * * ?" then         var hour = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState(now.minusHours(1), "mysql":).state as DecimalType //определяем диапазоны времени         if(now.getHourOfDay > 7 && now.getHourOfDay < 23)         {                 logInfo("TEST","sdm220_hourcounter_day = "+hour)                 postUpdate(sdm220_hourcounter_day, hour)         }         else         { //на границе диапазонов добавляем нулевые значения в график //так как в таблице в качестве primary key используется timestamp, между добавлениями данных в одну и ту же таблицу стоит пауза в одну секунду                 if(now.getHourOfDay==7)                 {                         postUpdate(sdm220_hourcounter_night, hour)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_night, 0)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_day, 0)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_day, hour)                 }                 else if(now.getHourOfDay==23)                 {                         postUpdate(sdm220_hourcounter_day, hour)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_day,0)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_night, 0)                         Thread::sleep(1000)                         postUpdate(sdm220_hourcounter_night, hour)                 }                 else                 {                         postUpdate(sdm220_hourcounter_night, hour)                 }         }         postUpdate(sdm220_hourcounter, hour) end  rule "Energy by day" when         Time cron "0 0 0 * * ?" then         var day = sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState(now.minusDays(1), "mysql":).state as DecimalType         //night counter, 00:00..07:00 + 23:00..00:00         var day2 = sdm220_actcounter.historicState(now.minusHours(17),"mysql":).state as DecimalType - sdm220_actcounter.historicState(now.minusDays(1), "mysql":).state as DecimalType + sdm220_actcounter.state as DecimalType - sdm220_actcounter.historicState(now.minusHours(1),"mysql":).state as DecimalType         //day counter, 07:00..23:00         var day1 = sdm220_actcounter.historicState(now.minusHours(1),"mysql":).state as DecimalType - sdm220_actcounter.historicState(now.minusHours(17),"mysql":).state as DecimalType         logInfo("TEST","sdm220_daycounter_day = "+day1)         logInfo("TEST","sdm220_daycounter_night = "+day2)         logInfo("TEST","sdm220_daycounter = "+day)         postUpdate(sdm220_daycounter, day)         postUpdate(sdm220_daycounter_day, day1)         postUpdate(sdm220_daycounter_night, day2) end 

Перед редактированием скрипта добавить нужные Items:

Number sdm220_hourcounter_day (gSDM220) Number sdm220_hourcounter_night (gSDM220) Number sdm220_daycounter_day (gSDM220) Number sdm220_daycounter_night (gSDM220) 

Теперь график почасового и посуточного расхода выглядит так:

На этом, пожалуй, все. В планах еще добавить подсчет расхода электроэнергии и денег за месяц по дневному и ночному тарифу и генерацию отчета с отправкой на почту.
ссылка на оригинал статьи https://geektimes.ru/post/288206/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *