Документация, примеры использования системы умного дома и управления нагрузкой и 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

Пример запроса данных из журнала 2.
Дайте мне все накопленные координаты (журнал 2) после времени 1363072608, порциями по 5 штук
сервер: 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
  • первая колонка содержит номер журнала.
  • вторая колонка время наступления события.
  • третья колонка - содержит в данном примере везде 3f - это тип записи, который говорит нам о том, что значение потенциала на датчике массы изменилось.
  • четвертая колонка содержит три цифры: 15,0,15 - это значение потенциала на упомянутом выше датчике.
  • цифра в последней колонке - это всегда CRC при работе с журналами.

В нулевом журнале устройств типа A,A-KIT могут содержаться различные типы записей, но нас, в данном случае, интересуют всего два типа

  • 17 - битовая переменная в качестве аргумента, по ней можно определить какие выходы устройства сейчас под напряжением.
  • 18 - сообщает нам о состоянии входящих линий , на которых могут быть датчики или просто кнопки для управления вариантом A.

Как подключиться к серверу

Для того, чтобы сервер мог выдать команды розетке - она должна подключиться к GPRS, соединиться с указанным IP, на котором слушает сервер и пройти процедуру входа на сервер.

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

Устанавливаем IP и порт своего сервера

В том случае, если вы используете свой сервер - вам надо прописать в конфигурацию нужный IP адрес и порт для соединения.

Формат команды: 43 "X","A", где , в кавычках, вместо X казываем ip, затем через запятую и в кавычках вместо A указываем порт.

Пример:
Хотим подключиться к серверу с ip: 123.123.123.123 на порт 21
Текст сообщения:
43 "123.123.123.123","21"
Внимание
Не забываем указывать IP,порт в кавычках.




Теперь о процедуре входа на сервере. Когда вы пропишите параметры на подключения - устройство начнет совершать попытки соединения с сервером. На нем, в логах, вы увидите попытки входа. Если это происходит идем далее:

Процедура входа, упрощенно:

клиент: 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. Если канал пропал - розетка поднимет его и заново начнет проверку пароля на сервере.

Предупреждения
Ваше устройство может не поддерживать команды, все зависит от версии прошивки устройства. Чтобы узнать версию прошивки вашего устройства используйте эту команду, а историю обновления прошивок можно изучить вот тут. При необходимости обновить код - изучайте вот это.