Анализ данных с электросчетчика Eastron SDM220 средствами ThingSpeak

Всем привет. В статье на geektimes я рассказывал, как подключиться к электросчетчику Eastron SDM220-Modbus и забрать с него данные по шине RS-485. Сегодня я хочу рассказать про сбор и анализ статистических данных о потреблении электричества в доме.

a64ad4b4b1b94ff4bc94dcdeb57d38d1.png

В качестве домашнего хаба для сбора данных я использовал тонкий клиент Centerm GI-945. Его плюсы — x86 архитектура (atom 1,6 GHz), 5 USB, 1G Ethernet, mini-pcie (поставил в него wifi-карту). С флешки грузится Ubuntu Server 14.04.

c0876cd1bfcb41d78e2c7efea00ef652.jpg

75408e5d41944247aa3587251de07295.jpg

Через USB-RS485 адаптер к «серверу» подключен электросчетчик. Опрос счетчика делает скрипт на Python, за основу взял этот пример. Для работы скрипта нужна библиотека pyModbus

Установка библиотеки
sudo add-apt-repository ppa: fkrull/deadsnakes-python2.7
sudo apt-get update
sudo apt-get upgrade

apt-get -y install python-pip
apt-get install python2.7-dev

pip install -U pymodbus


Скрипт запускается по cron раз в минуту, забирает данные (напряжение, ток, мощность и учтенная энергия) со счетчика и отправляет их на сайт ThingSpeak.

На сайте предварительно нужно зарегистрироваться, создать свой канал данных channel и назвать поля fields. Также для записи данных в канал понадобится write API key.

e1c2f6e1cb46408aa0802e5c16089a19.png

Код скрипта на Python
#!/usr/bin/python2
import struct
import pymodbus.client.sync
import binascii
import time
import sys
import urllib

def read_float_reg (client, basereg, unit=1):
resp = client.read_input_registers (basereg,2, unit=1)
if resp == None:
return None
# according to spec, each pair of registers returned
# encodes a IEEE754 float where the first register carries
# the most significant 16 bits, the second register carries the
# least significant 16 bits.
return struct.unpack ('>f', struct.pack ('>HH',*resp.registers))

def fmt_or_dummy (regfmt, val):
if val is None:
return '.'*len (regfmt[2]%(0))
return regfmt[2]%(val)

def main ():
regs = [
# Symbol Reg# Format
('V:', 0×00, '%6.2f'), # Voltage [V]
('Curr:', 0×06, '%6.2f'), # Current [A]
('Pact:', 0×0c, '%6.0f'), # Active Power («Wirkleistung») [W]
('Papp:', 0×12, '%6.0f'), # Apparent Power («Scheinl.») [W]
('Prea:', 0×18, '%6.0f'), # Reactive Power («Blindl.») [W]
('PF:', 0×1e, '%6.3f'), # Power Factor [1]
('Phi:', 0×24, '%6.1f'), # cos (Phi)? [1]
('Freq:', 0×46, '%6.2f'), # Line Frequency [Hz]
('Wact:', 0×0156, '%6.2f'), # Energy [kWh]
('Wrea:', 0×0158, '%6.2f'), # Energy react [kvarh]
]

cl = pymodbus.client.sync.ModbusSerialClient ('rtu',
port='/dev/ttyUSB0', baudrate=9600, parity='N', stopbits=1,
timeout=0.8)

values = [ read_float_reg (cl, reg[1], unit=1) for reg in regs ]
outvals = list ((' '.join ([fmt_or_dummy (*t) for t in zip (regs, values)])).split ())
params = urllib.urlencode ({'key': 'xxxxxxxxxxxxxxxx', 'field1': outvals[0], 'field2': outvals[1], 'field3': outvals[2], 'field4': outvals[8]})
f = urllib.urlopen («api.thingspeak.com/update», data=params)
print (outvals)
sys.stdout.flush ()

if __name__ == '__main__':
main ()


Скрипт забирает все доступные параметры со счетчика, но на сайт передаются только основные, при желании можно передавать все.

Результат сразу будет отображаться на сайте (на скрине показана статистика за некоторое время, при первом опросе там будет только одна точка со значением)

55b6e7c5616343289515879508fd9248.png

По умолчанию графики отображают последние 60 показаний, что при опросе раз в минуту дает результат за последний час. Для каждого графика можно настроить отображение

738176a12bf844d0aa66287b1ced9891.png

Для напряжения настроил статистику за 6 часов с усреднением по 10 значений и сглаживанием кривой (spline).

Видно, что график потребленной энергии — это постоянно возрастающая кривая, а хотелось бы видеть расход за час, сутки и месяц, для этого на сайте есть аналитика, основанная на движке MATLAB и возможность запускать события по времени.

Для сбора почасовой статистики сделал следующее:

  1. Создал второй канал PowerStatistic;
  2. В Apps → MATLAB Analysis создал скрипт, который берет текущее значение энергии и вычитает из него значение час назад. Результат заносится в поле канала;
  3. В Apps → Time Control создал событие GetPowerPerHour, которое будет каждый час в 00 минут запускать матлабовский скрипт.

Скрипт PowerPerHour
% ID исходного канала, в который помещаются данные со счетчика, если канал приватный, нужно указать Read API Key
readChannelID = 154291;

% ID канала для записи обработанных данных (PowerStatistic)
writeChannelID = 157182;
writeAPIKey = 'xxxxxxxxxxxxxxxxxx';

%% Read Data %%
data1 = thingSpeakRead (readChannelID, 'Fields', 4);
data2 = thingSpeakRead (readChannelID, 'Fields', 4, 'NumMinutes', 60);
value = data1-data2(1);

%в data1 читаем последнее значение из 4-го поля (Energy)
%чтение в data2 сделано криво, но по другому я пока не придумал, читаются последние 60 значений (за час) и берется первое из них

%% Analyze Data %%
% пришлось добавить округление до двух знаков, так как несмотря на то, что в исходном массиве значения лежат округленные до двух знаков после запятой, результат вычитания почему-то выглядел так: 0.2700000000000031
analyzedData = round (value,2);

%disp можно использовать для отладки данных
%disp (analyzedData);

Если в analyzedData одно значение, а не вектор, оно будет записано в первое поле канала. Для записи в другие поля нужно добавить 'Fields',2, например.
%% Write Data %%
thingSpeakWrite (writeChannelID, analyzedData, 'WriteKey', writeAPIKey);


На сайте есть неприятный косяк, для применения скрипта есть кнопка Save&Run, которая при каждом запуске делает запись в канал, поэтому до полной отладки строку записи лучше закомментировать, однако даже когда скрипт готов, его нельзя просто сохранить без запуска, а запуск скрипта сразу занесет данные в канал. Удалить индивидуальные данные из канала тоже нельзя. Этот вопрос уже поднят на форуме проекта, но пока не исправлен.

cbc93c3f1fa84c2baaf0fe7cdc054b49.png

Настройки запуска по расписанию, скрипт запускается каждый час. На то, что начало запуска в 12.00 можно не обращать внимание.

Смотрим в канале результат:

6aadce875ded468485c91604b4e48a74.png

Для этого графика в настройках указан Type: column для отображения расхода электроэнергии по часам. Всплывающее окно соответствует пику потребления в 12 часов (курор на скрине не отобразился).

Аналогичным образом работает скрипт, собирающий статистику за сутки. Скрипт запускается в 00:01 каждого дня и суммирует 24 показания из почасового архива.

Скрипт PowerPerDay
readChannelID = 157182;
readAPIKey = 'zzzzzzzzzzzzzzzzzzzzz';

writeChannelID = 157182;
writeAPIKey = 'xxxxxxxxxxxxxxxxxxxx';

%% Read Data %%
% читаем последние 24 значения из первого поля канала
data = thingSpeakRead (readChannelID, 'ReadKey', readAPIKey, 'Fields',1, 'NumPoints',24);

%% Analyze Data %%
%суммируем
analyzedData = sum (data);

%disp (analyzedData);

%% Write Data %%
thingSpeakWrite (writeChannelID, analyzedData, 'WriteKey', writeAPIKey, 'Fields',2);


Для ThingSpeak также есть приложения под Android. Для просмотра последних значений мне понравился Pocket IoT, а для графиков — ThingView. Есть также пара виджетов, но они какие-то кривые.

» Канал PowerMeter
» Канал PowerStatistic

На этом, пожалуй, все. Статья не претендует на tutorial, так как я только начал знакомиться с возможностями ThingSpeak, любые дополнения, замечания и правки приветствуются.

Комментарии (2)

  • 9 сентября 2016 в 13:05

    0

    Расскажите в следующих частях чего интересного/неожиданного намерили.
    • 9 сентября 2016 в 13:08

      0

      На отдельную часть это не тянет, но в целом статистика забавная. Видно, как работает холодильник ночью, сколько утром потребляют чайник, тостер и микроволновка. Кстати, сдавал этот счетчик на метрологическую поверку, в свой первый класс точности входит с трехкратным запасом.

© Habrahabr.ru