[Из песочницы] Автоматизация снятия показаний со счетчиков воды

Все знают, что лень двигатель прогресса. Так случилось и в моем случае.ac631ab0e8864b46bb2eb9f577935a82.JPG

В квартире присутствует 6 точек раздачи воды (3 холодные и 3 горячие). На каждой из точек стоит счетчик.Каждые 2 счетчика спрятаны за люками скрытого монтажа, один из люков находится за зеркалом, которое нужно снять, чтобы до него добраться.

Вот пара люков:

1ab0ec8c2808425c8e15d093114a7ebf.JPG

Раз в месяц с 20 по 25 число необходимо снимать показания со всех счетчиков и отправлять данные в Управляющую Компанию на бланке определенного образца.

В какой-то момент мне надоело открывать люки, снимать зеркало и было решено автоматизировать снятие показаний.Сначала перерыл интернет на предмет существующих устройств автоматизации. Нашел только один для меня подходящий — Счетчик импульсов-регистратор «Пульсар» 6-ти канальный. Надо сказать, что стоит он почти 6000 рублей! На самом деле в розницу нигде я его не видел, так как слишком специфический продукт и предполагается, что закупать их будут ТСЖ на все квартиры в доме. Попытался его заказать через интернет в разных местах, но каждый раз, как только доходило до доставки, продавец пропадал. Как я понял, они не любят работать с «физиками», либо был не слишком настойчив.Ну, нет, так нет — сделаем сами, да еще и дешевле.

Тут то и пригодилась Arduino Mega 2580 с Ethernet модулем, которая была когда-то куплена для различных экспериментов.

Когда делали ремонт в квартире, от каждой точки, где имеются счетчики, до щитка на лестничной клетке, были проложены кабели типа UTP cat 5e. Это было одно из требований контролирующей организации, чтобы в будущем снимать все показания централизованно. Будущее все никак не наступает, а провода пригодились.

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

В итоге, что мы имеем:

Счетчики воды Arduino Mega 2580 Arduino Ethernet 3.0 Бокс для Arduino Блок питания Шлейф для протягивания из слаботочного щитка в шкаф к Arduino. Домашний сервер на Debian с Lighttpd и Mysql Сами счетчики такие: adc2156ec7f3468ab1cb6cfe8cbf8bd6.JPG

Экспериментальным путем было определено, что счетчики работают не просто, а очень просто. Когда последний разряд меняет свое значение с 9 на 0, замыкается геркон внутри счетчика. В таком состоянии он находится до того, пока значение последнего разряда не станет равным 3. Т.е. фактически нам надо фиксировать момент перехода из состояния «разомкнуто» в состояние «замкнуто». Заострю внимание, что мы фиксируем ТОЛЬКО факт перехода из одного состояния в другое, потому что система может обесточиться, да и вообще, мало ли какие могут быть коллизии.

В момент замыкания геркона, Arduino по HTTP вызывает простенький perl-скрипт на сервере, где крутится lighttpd. Скрипт записывает в базу данных этот момент. Другой скрипт позволяет смотреть текущее состояние счетчиков.

Скетч Arduino с комментариями:

#include #include #include // Эту библиотеку необходимо скачать тут: https://github.com/thomasfredericks/Bounce-Arduino-Wiring

byte mac[] = {0×90,0xA2,0xDA,0×0E,0xF1,0×92}; // MAC-адрес нашего устройства (написан на наклейке платы Ethernet shield) IPAddress ip (192,168,1,11); // IP адрес, если вдруг не получится получить его через DHCP //IPAddress server (192,168,1,10); // ip-адрес удалённого сервера (использовался, пока не было имени) char server[] = «smarthome.mydomain.ru»; // Имя удалённого сервера char request[40]; // Переменная для формирования ссылок int CounterPin[6] = {22,23,24,25,26,27}; // Объявляем массив пинов, на которых висят счетчики char *CounterName[6] = {»0300181»,»0293594»,»0300125»,»0295451»,»0301008»,»0293848»}; // Объявляем массив имен счетчиков, которые мы будем передавать на сервер Bounce CounterBouncer[6] = {}; // Формируем для счетчиков Bounce объекты EthernetClient rclient; // Объект для соединения с сервером

void setup () { //Serial.begin (9600); for (int i=0; i<6; i++) { pinMode(CounterPin[i], INPUT); // Инициализируем пин digitalWrite(CounterPin[i], HIGH); // Включаем подтягивающий резистор CounterBouncer[i].attach(CounterPin[i]); // Настраиваем Bouncer CounterBouncer[i].interval(10); // и прописываем ему интервал дребезга } // Инициализируем сеть if (Ethernet.begin(mac) == 0) { Ethernet.begin(mac, ip); // Если не получилось подключиться по DHCP, пробуем еще раз с явно указанным IP адресом } delay(1000); // даем время для инициализации Ethernet shield }

void loop () { delay (1000); // Задержка в 1 сек, пусть будет :) // Проверяем состояние всех счетчиков for (int i=0; i<6; i++) { boolean changed = CounterBouncer[i].update(); if ( changed ) { int value = CounterBouncer[i].read(); // Если значение датчика стало ЗАМКНУТО if ( value == LOW) { //Serial.println(CounterPin[i]); sprintf(request, "GET /input.pl?object=%s HTTP/1.0", CounterName[i]); // Формируем ссылку запроса, куда вставляем имя счетчика sendHTTPRequest(); // Отправляем HTTP запрос } } } }

// Функция отправки HTTP-запроса на сервер void sendHTTPRequest () { if (rclient.connect (server,80)) { rclient.println (request); rclient.print («Host:»); rclient.println (server); rclient.println («Authorization: Basic UmI9dlPnaJI2S0f=»); // Base64 строка, полученная со значения «user: password» rclient.println («User-Agent: Arduino Sketch/1.0»); rclient.println (); rclient.stop (); } } На сервере крутится: Debian, Lighttpd, Mysql. В свою очередь на нем имеется два perl-скрипта: один для записи состояний счетчиков в базу, второй для вывода текущих показаний.

input.pl

#!/usr/bin/perl -w

use strict; use CGI: Fast; use DBI;

while (my $q = CGI: Fast→new) { main ($q); }

sub main { my $q = shift; my $dbh = DBI→connect («dbi: mysql: database=smart_home; mysql_client_found_rows=1; mysql_enable_utf8=1; mysql_socket=/var/run/mysqld/mysqld.sock», 'dbname', 'password', { RaiseError => 1, AutoCommit => 1, mysql_multi_statements => 1, mysql_init_command => q{SET NAMES 'utf8'; SET CHARACTER SET 'utf8'} }) or die «Cannot connect»; $dbh→{mysql_auto_reconnect} = 1; print «Content-Type: text/html; charset=UTF-8\n\n»; print «OK\n»; my $object = $q→param («object»); if ($object) { $dbh→do (q{INSERT INTO water_count (object) VALUES (?)}, undef,$object) or die $dbh→errstr; } } result.pl

#!/usr/bin/perl -w

use strict; use CGI: Fast; use DBI;

# массив стартовых показаний счетчиков my $start = { »0300125» => 102.53, »0301008» => 75.31, »0300181» => 65.92, »0293594» => 54.51, »0293848» => 55.04, »0295451» => 87.43 };

while (my $q = CGI: Fast→new) { main ($q); }

sub main { my $dbh = DBI→connect («dbi: mysql: database=smart_home; mysql_client_found_rows=1; mysql_enable_utf8=1; mysql_socket=/var/run/mysqld/mysqld.sock», 'dbname', 'password', { RaiseError => 1, AutoCommit => 1, mysql_multi_statements => 1, mysql_init_command => q{SET NAMES 'utf8'; SET CHARACTER SET 'utf8'} }) or die «Cannot connect»; $dbh→{mysql_auto_reconnect} = 1; print «Content-Type: text/html; charset=UTF-8\n\n»; print «Текущие показания счетчиков:
»; my $sql = «SELECT count (*) as c, object FROM water_count group by object»; my $sth = $dbh→prepare ($sql); $sth→execute; while (my ($count, $object) = $sth→fetchrow_array ()) { $start→{$object} = sprintf (»%.2f»,$start→{$object}+$count/100); } $sth→finish; foreach my $object (keys $start) { my ($intcurrent,$fine) = split (/\./,$start→{$object}); print »$object $intcurrent.$fine
\n»; } } Mysql база с одной таблицей:

CREATE TABLE `water_count` ( `object` varchar (20) NOT NULL DEFAULT '', `datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8 В таблице есть только два поля. Первое — название объекта (в нашем случае это номер счетчика). Второе — дата и время в формате TIMESTAMP, которые заполняются автоматически, когда происходит вставка строки.

Вот, собственно, и все. Теперь в любой момент я могу узнать какое значение имеют все счетчики, просто зайдя браузером на домашний сервер.

Что дальше? Дальше хочется ежемесячную автоматическую распечатку на заполненном бланке.Так же хочется подключить счетчик электроэнергии с передачей данных в Мосэнергосбыт, а потом и с их оплатой.Статистика, графики и прочие радости работы с данными.

© Habrahabr.ru