Документация, примеры использования системы умного дома и управления нагрузкой и gsm сигнализации. Работа с проектом Контроль Температуры |
Тут описан наш вариант реализации серверной части. Он достаточно универсальный и держит связь с устройствами нескольких поколений и типов.
Все работает - как большая машина состояний.
Устройство занято тем, что обеспечивает поднятие и удержание канала по gprs в сторону нашего сервера.
Сервер, после прохождения розеткой процедуры авторизации, пропускает ее по сценарию, который жестко прописан для разных типов устройств.
Если сервер чего-то не попросит от розетки - она это сама по себе не отдаст.
Протокол полностью текстовый - вы можете, с помощью обычного telnet, выступать в роли клиента для сервера или, скажем, можете отвечать на запросы розеток вручную.
Все чувствительные данные, что передает на сервер розетка - подписаны контрольной суммой.
Каждая строка завершается числом, который и есть контрольная сумма. Если вы будете писать эмулятор розетки - вам надо будет создавать контрольную сумму. Пример реализации на C-псевдокоде:
void crc(char *msg) { char *ms; int32 crc=0; ms=msg; while(*ms) { crc+=*ms; ms++; } printf(bputc,"%s %lu\r\n",msg,crc); }
Сервер же, получив строку, в которой надо проверить контрольную сумму, должен выполнить код, чей алгоритм совпадает с данным Perl-псевдокодом:
sub crc { my $str=shift; my $k=0; my $k1=0; while($k<length $str) { $k1+=unpack("C",substr $str, $k ,1); $k++; } return $k1; }
В случае обычной работы с розетками (через сервер) вы столкнетесь с подсчетом CRC только при работе с журналами данных.
Что такое журнал данных.
Устройство имеет несколько энергонезависимых хранилищ данных. Они небольшие, потому-что считалось, что розетка, умеющая отдавать данные, будет находится
в постоянном соединении с сервером (если данные важны) или не будет вовсе. На случай временных падений GSM сети, отсутствия положительного баланса, розетка будет накапливать данные в этих журналах. В них помещается несколько сотен записей.
Журналы бывают нескольких типов. Все зависит от модели устройства и данных, которые оно может накапливать.
Например, на устройствах со спутниковым приемником , есть журнал 2, в нем хранятся координаты, скорость перемещения.
В простейщих (не B-DIN, не 1U-CAN) устройствах с температурными датчиками есть журнал 3, в нем хранятся замеры температуры за последние дни.
На всех устройствах присутствует журнал типа 0.
Это журнал, куда, обычно, попадают различные события, происходящие реже, чем раз в минуту, такие как информация о пропадании питании или его появлении, о том, что устройство перегружалось (и причина перезагрузки), о срабатывании внешних датчиков или кнопок управления.
Журналы имеют следующий примерный вид:
дата-время-записи данные1 данные2 данныеX CRC
Время в журналах хранится в виде целого числа - разницы между временем устройства на момент события и началом эпохи Unix (The Unix Epoch, 1 января 1970 00:00:00 GMT).
Вот C-псевдокод, который используется для генерирования этого числа:
unsigned long DateToBinary(tm_struct *datetime) { unsigned long iday; unsigned long val; iday = 365 * (datetime->tm_year - 70) + DaysToMonth[datetime->tm_mon] + (datetime->tm_mday - 1); iday = iday + (datetime->tm_year - 69) / 4; if ((datetime->tm_mon > 1) && ((datetime->tm_year % 4) == 0)) { iday++; } val = datetime->tm_sec + 60 * datetime->tm_min + 3600 * (datetime->tm_hour + 24 * iday); return val; }
Вы можете установить время в устройстве самостоятельно (см. документацию Встроенные часы) как через sms так и через tcp/ip
Для того, чтобы получить данные из журнала вам надо сделать запрос, в котором будет указан номер журнала, время, начиная с которого вас интересуют данные и размер порции данных (в количестве записей).
Команда для получения данных из журнала работает только через tcp/ip и называется nextall
сервер: nextall 2 1363072608 5
В ответ вам придет блок указанной или меньше длинны. Оканчиваться он будет строкой, содержащей нули во всех полях данных и времени.
Если пришла только одна строка, содержащая нули- значит нет пока-что данных позже заказанного вами времени.
Если пришло столько строк, сколько заказали - есть смысл повторить запрос с обновленной датой, возможно есть еще данные, которые вы не получали.
сервер: nextall 2 1363072608 5 клиент: 2 1363072668 60516140 28570082 11 1621 клиент: 2 0 0 0 0 370
Мы просили 5 записей, получили меньше - а значит, устройство пока-что еще не накопило более свежей информации (что нормально для устройств, сливающих информацию раз в минуту)
В случае с устройством типа A, A-KIT - у нас будет всего один журнал, типа 0. Он имеет следующий формат:
дата-время-записи тип записи аргумент CRC
Вот, для примера, кусок ответа на запрос журнала 0 устройства, которое оснащено функцией проверки наличия-отстутствия массы на корпусе грузового автомобиля.
клиент: 0 1363054006 3f 15 907 клиент: 0 1363055434 3f 0 859 клиент: 0 1363067622 3f 15 915
В нулевом журнале устройств типа A,A-KIT могут содержаться различные типы записей, но нас, в данном случае, интересуют всего два типа
Для того, чтобы сервер мог выдать команды розетке - она должна подключиться к GPRS, соединиться с указанным IP, на котором слушает сервер и пройти процедуру входа на сервер.
В случае, если у вас устройство с поддержкой температуры - для того, чтобы отконфигурировать устройство вам придется прочитать документацию.
В том случае, если вы используете свой сервер - вам надо прописать в конфигурацию нужный IP адрес и порт для соединения.
Формат команды: 43 "X","A", где , в кавычках, вместо X казываем ip, затем через запятую и в кавычках вместо A указываем порт.
43 "123.123.123.123","21"
Теперь о процедуре входа на сервере. Когда вы пропишите параметры на подключения - устройство начнет совершать попытки соединения с сервером. На нем, в логах, вы увидите попытки входа. Если это происходит идем далее:
Процедура входа, упрощенно:
клиент: login username pass если все ок сервер: начинает выполнять сценарий если не ок: сервер: командует розетке отключиться и делать следующую попытку не раньше чем через X секунд
Более подробно:
Каждое устройство имеет свой сериный номер.
Его и используем в качетсве username
Вот пример лога с нашего сервера со входом какого-то устройства и получением первой команды после удачной проверки пароля:
12/03/13 05:09:32 [0] <-login 2415 qtznn 0 [20] 12/03/13 05:09:32 [2415] ->nextall 3 1363064705 5 [24]
login сериный номер пароль 0 опциональный аргмент ноль - в данном случае это битовая переменная, ее наличие и содержимое важно только для температурных устройств. Если у вас такое - сообщите мне, я опишу подробнее. Иначе - игнорируйте его при поддержке на своем сервере.
Если бы пароль и серийный номер не совпали сервер ответил бы командой logoff X, где X - количество секунд, которое устройство должно выждать доследующего коннекта.
После входа на сервер устройство получает от него все необходимые команды (например ВКЛЮЧЕНИЯ или ВЫКЛЮЧЕНИЯ). Выполняет их и отдает ответы на сервер. Когда сервер заканчивает со сценарием он выдаст розетке команду sleep При ее получении розетка перестает общаться с сервером на время, установленное соответствующей командой конфигурации.
По прошествии этого времени розетка проверит, есть ли поднятый канал до сервера и поднимет его при необходимости. Если канал был в наличии - она выдаст команду u FLAG, где флаг - полная аналогия последнего аргумент из команды login. Если канал пропал - розетка поднимет его и заново начнет проверку пароля на сервере.