Работа с Народным Мониторингом на Python с Raspberry Pi

  • Tutorial
Пытаясь подключить свой датчик температуры DS18B20 к своей умной теплице, я обнаружил, что в интернете нет полной инструкции по подключению этого датчика посредством языка программирования Python. Использую его, так как работаю с платформой Raspberry Pi. Я решил эту проблему устранить. Оказывается работать с TCP не так сложно, но нужно понимать, что и для чего мы делаем. Двухчасовой танец с бубном меня явно выбесил. Так что здесь, помимо самой программной части, я хочу рассказать весь алгоритм от начала до конца. Думаю, что другие датчики работают похоже, поэтому большая статьи будет для всех одинакова. Надеюсь, что если вы захотите подключить свой датчик, Вам уже бубен не понадобится:) И так, давайте приступим, прошу Вас под Хаброкат.

Шаманство с датчиком


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

import os
tfile=open("/sys/bus/w1/devices/28-000000d7970b/w1_slave")
ttext=tfile.read()
tfile.close()
temp=ttext.split("\n")[1].split(" ")[9]
temperature=float(temp[2:])/1000
print temperature

Не забываем заменить данные на свой датчик.

Как мы можем заметить, значение температуры принимает переменная temperature (кто бы мог подумать), что и понадобится нам дальше.

Колдуем с мониторингом


Ну во первых нужно зарегистрироваться narodmon.ru, тем, кто ещё это не сделал. API сервиса предлагает нам передавать данные по протоколу TCP. Так и поступим. Нас просят передать текст следующего формата:

#MAC[#NAME][#LAT][#LNG][#ELE]\n
#mac1#value1[#time1][#name1]\n
...
#macN#valueN[#timeN][#nameN]\n
##

Но по факту нам нужно передать всего три параметра: MAC устройства, имя датчика и его значение. Остальное не обязательно, и не очень нам нужно.

В первой строке нам нужно передать решётку, MAC и символ перевода строки \n.
Во второй и последующих строках мы опять передаём решётку, имя датчика, опять решётка и показания датчика. Завершаем это символом перевода строки \n.
В последней строке надо передать две решётки, для завершения пакета.

В итоге формат остаётся таким:

#MAC\n
#mac1#value1\n
#macN#valueN\n
##

Пишем программу на Python


Программу мы будем писать на Python 2. Алгоритм будет такой. Получаем данные с датчика и записываем в переменную temperature. Затем мы формируем пакет и отправляем его на сервер Народного Мониторинга. Запускать скрипт будем каждые 10 минут (минимальный разрешённый интервал отправки показаний 5 минут) через cron.

Отправка происходит так (пример приведённый на сайте мониторинга):

Код скрипта отправки
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# by Roman Vishnevsky aka.x0x01 @ gmail.com

import socket

# MAC адрес устройства. Заменить на свой!
DEVICE_MAC = '0123456789012'

# идентификатор устройства, для простоты добавляется 01 (02) к mac устройства
SENSOR_ID_1 = DEVICE_MAC + '01'
SENSOR_ID_2 = DEVICE_MAC + '02'

# значения датчиков, тип float/integer
sensor_value_1 = 20
sensor_value_2 = -20.25

# создание сокета
sock = socket.socket()

# обработчик исключений
try:
    # подключаемся к сокету
    sock.connect(('narodmon.ru', 8283))

    # пишем в сокет еденичное значение датчика
    sock.send("#{}\n#{}#{}\n##".format(DEVICE_MAC, SENSOR_ID_1, sensor_value_1))

    # пишем в сокет множественные значение датчиков
    # sock.send("#{}\n#{}#{}\n#{}#{}\n##".format(DEVICE_MAC, SENSOR_ID_1, sensor_value_1, SENSOR_ID_2, sensor_value_2))

    # читаем ответ
    data = sock.recv(1024)
    sock.close()
    print data
except socket.error, e:
    print('ERROR! Exception {}'.format(e))


Подключаемся мы к серверу narodmon.ru:8283

В итоге у нас получается вот такой скрипт:

Код готового скрипта
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import socket
import os
import fnmatch

# MAC адрес устройства. Заменить на свой!
DEVICE_MAC = 'FF:FF:FF:FF:FF:FF'

#Имена датчиков
SENSOR_ID_1 = 'T1'
SENSOR_ID_2 = 'T2'

#Читаем значения датчиков
temperature = []
IDs = []
for filename in os.listdir("/sys/bus/w1/devices"):
  if fnmatch.fnmatch(filename, '28-031652ddbdff'):
    with open("/sys/bus/w1/devices/" + filename + "/w1_slave") as fileobj:
        lines = fileobj.readlines()
    if lines[0].find("YES"):
        pok = lines[1].find('=')
        temperature.append(float(lines[1][pok+1:pok+7])/1000)
        IDs.append(filename)
    else:
          logger.error("Error reading sensor with ID: %s" % (filename))

temperature2 = []
for filename in os.listdir("/sys/bus/w1/devices"):
  if fnmatch.fnmatch(filename, '28-011563e8d2ff'):
    with open("/sys/bus/w1/devices/" + filename + "/w1_slave") as fileobj:
        lines = fileobj.readlines()
    if lines[0].find("YES"):
        pok = lines[1].find('=')
        temperature2.append(float(lines[1][pok+1:pok+7])/1000)
        IDs.append(filename)
    else:
          logger.error("Error reading sensor with ID: %s" % (filename))

sock = socket.socket()

#Подключаемся
try:
    sock.connect(('narodmon.ru', 8283))
#Создаём маску, заносим в неё данные и передаём их
    sock.send("#{}\n#{}#{}\n#{}#{}\n##".format(DEVICE_MAC, SENSOR_ID_1, str(temperature)[1:-1], SENSOR_ID_2, str(temperature2)[1:-1]))

#Получаем ответ
    data=sock.recv(1024)
    sock.close()
    print data
except socket.error, e:
    print('ERROR! Exception {}'.format(e))

print str(temperature)[1:-1]
print str(temperature2)[1:-1]


Вот так выглядит отправка данных с двух датчиков. Если дать датчику название, начинающееся на T, то сервер сам определит, что это датчик температуры.

Теперь нам нужно добавить датчик в cron. Набираем: crontab -e и добавляем туда вот такую строчку:

*/10 * * * * sudo python /home/pi/narod.py

Ждём пока скрипт запустится.

Теперь идём сюда narodmon.ru/ip и смотрим передались ли данные. Если всё в порядке, то нажимаем на главной странице в меню кнопку «Добавить устройство» и указываем MAC. Теперь мы можем всё настроить по вкусу (название, тип, местоположение и т.д.). Сделать датчик публичным можно через сутки после начала передачи показаний.

На этом всё. Желаю Вам удачи в подключение датчиков. Делайте это чаще, ведь так удобно из дома заранее посмотреть температуру в том месте, куда ты собираешься.

До новых встреч :)

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 30

    0
    ИМХО в статье на хватает линка на Ваш работающий датчик. Можете опубликовать?
      0
      Попробую. Сейчас зима, теплица работает с перебоями.
      0

      Даже в данном случае, как систему мониторинга я бы выбрал Zabbix, тем более на то есть все ресурсы

        0
        Nexx WT3020H + RODOS-5 (MP707) Результат в Zabbix. Сейчас хочу SMALL METEO V4 прикупить.
        –1

        Сейчас бы в 2017 писать на python 2

          +1
          На таком языке нашёл я все примеры.
            0
            А, ну в таком случае ничего не имею против
            +2
            В Raspbian-e он есть по умолчанию. Меньше проблем, никаких левых библиотек качать не нужно. Так что выбор вполне оправдан.
              0
              Python3 там так же есть, все «DIY»-библиотеки для третьего питона есть, синтаксис у них лучше и они быстрее. Так что выбор оправдан только тем, что автор не нашёл ничего другого. Я не чтобы поогрызаться, а к тому что Python3 уже всюду предпочтительнее.
            +6
            здравствуйте, уважаемый автор,

            Чтобы метеостанция не сдохла через полгода-год от самозапиливающейся флэшки, настоятельно рекомендую монтировать её в read-only, см., например, https://geektimes.ru/post/283802/. Остальные рекомендации помещаю в спойлеры.

            про 1-wire, sysfs и hardcode
            Несмотря на имеющиеся ссылки, неплохо было бы посвятить хотя бы один абзац текста описанию того, что DS18B20 работает через интерфейс 1-wire, что доступ к нему получаете через sysfs, и что для этого подгружаются модули w1-gpio и w1_therm. Для тех, кто предпочитает активировать 1-wire по-простому, можно указать и на утилиту raspi-config. Хорошо бы объяснить смысл параметров типа pullup и питанию. Те, кто раньше не работал с датчиками через sysfs, наверняка оценят и разъяснения к схеме именования, по которой все устройства появляются в /sys/bus/w1/devices, а каждому устройству сопоставляется каталог вида YY-xxxxxxxxxxxx, где YY суть Family Code (28 для DS18B20), а остальное — уникальный номер устройства. И если Вы свои устройства зашиваете в скрипт хардкодом, предупредите, пожалуйста, об этом явно в комментариях. Хотя резиденты местного клуба и так разберутся, но для гостей портала все вышеперечисленное не будет лишним.

            про измеряемые температуры
            Я бы указал на ограничения по рабочим температурам, длине проводов и т.д. У самого одноплатника есть ограничения по работе, см., например, https://habrahabr.ru/post/318486/ и комментарии.

            Если спросить поисковик про «DS18B20 Raspberry Pi», будет просто взрыв. Та статья, что Вы выбрали, содержит достаточно абсурдное утверждение о якобы измеряемом диапазоне -10°C..+85°C. Это совершенно неверно, потому что на самом деле DS18B20 измеряет диапазон -55°C to +125°C, но только в диапазоне от -10 до +85 его точность заявлена как ±0.5°C (т.е. 1°C). Думаю, что в Вашей геолокации -10°C это вообще несерьёзно, неужели не обратили внимания?

            про стиль naive coding
            Конечно, стиль naive coding гораздо более понятен читателям, но всё-таки финальный скрипт я бы организовал так, чтобы перед сетевой частью все файлы sysfs были уже закрыты. Что будет при наползании следующего прогона на предыдущий, кстати? Мало ли чего, народный сервер придержит Вам транзакцию, скриптина зависнет минут на 15, за ней вторая, и т.д. У меня утилита feh недели за три из-за течки памяти сжирает всю оперативную память и флэшка не сдохла только потому, что работает в read-only с отключённым swap.


            Двухчасовой танец с бубном меня явно выбесил
            Уверяю: у Вас впереди много интересного:) Тем не менее, плюсую авансом.

            PS
            Лично мне по теме понравился вот этот tutorial: Raspberry Pi Tutorial Series: 1-Wire DS18B20 Sensor.
              +2
              Учту ошибки. Вечером исправлю)
                0
                Поправьте заголовок заодно, пожалуйста.
                  0
                  Как именно?
                    0
                    с народнЫМ мониторингОМ (кем/чем)
                0
                Вам ещё про параметр gpiopin ниже порекомендовали, это к вопросу 1-wire.
              –1
              Этот датчик разве не может работать как триггер? Насколько помню, что 1820, что 1821 — примерно одного класса устройства. Имел опыт работы с 18С21 (может быть неточно, там ещё что-то было в маркировке) в триггерном режиме. Суть в том, что датчик можно запрограммировать, так, что он перестаёт выдавать по 1-wire температуру, но выход принимает только два значения: лог.1 и лог.0. Запрограммировать верхний предел температуры и нижний можно специальным программатором (например, тут описано http://www.rtcs.ru/article_detail.asp?id=73). Точность в таком случае 1 градус, что для Вашего случая (насколько понял, теплица) вполне подойдёт для автоматической регулировки без каких либо микроконтроллеров и прочего — просто усилитель на транзисторе и реле, управляющее обогревом.
              Конечно, если микроконтроллер/компьютер уже есть, то всё это и на нём можно сделать, я просто хотел сказать, что для регулировки температуры не нужно закупать компьютер.
                0
                А на narodmon что передавать: 0 или 1?
                  +1
                  Я просто думал, что датчики ставят как раз с целью автоматизации — чтобы была автоматическая регулировка. Но если нужен именно мониторинг значений температуры — то триггерный режим не подойдёт. Правда, можно передавать 0 или 1 — только трактовать это надо будет так — 1 — превышение TH, 0 — температура ниже TL (или наоборот, инвертировать можно хоть логикой в программе, хоть аппаратно).
                  0
                  А где об этом режиме почитать?
                  Гугл выдает именно эту страницу.
                    +1
                    Упс… я поленился почитать подробности в документации. На самом деле: DS1820 — термометр, DS1821 — термостат. Т.е. именно 1820 использовать в таком режиме нельзя, а 1821 — можно.
                    +1
                    1820 работает только в режиме измерителя температуры, в нем есть сигнализация о достижении/превышении температуры, но не физический триггер для подключения чего то напрямую.
                    0
                    Может я не так понял — подскажите, а MAC устройства это разве не MAC самой малинки которая данные отправляет? Если да, то почему вы не берете адрес из системы и вбиваете его руками?
                      0
                      Можно и автоматизировать. Просто я обычно не меняю WIFI адаптеры на малинке, так что MAC не меняется. Каждый раз проверять его не нужно.
                        0
                        Я вообще то был уверен что программисты унифицируют код в порядке хорошего тона, чтобы голова не болела о таких мелочах. То есть вот случись чего с вашей малинкой или с wifi адаптером, или кто-то воспользуется вашим скриптом — придётся править этот кусок кода руками. Да банально — вам пришлось лезть в систему и копировать оттуда MAC адрес сетевухи в ручную! Не лень разве было?)
                          0
                          Я думаю, Вы конечно правы. Просто в первую очередь я делал это для себя, и такое не предусмотрел. Добавлю это в статью. Спасибо )
                            +1
                            Опять же) если вы делитесь своим творением с окружающими, то это уже точно не для вас одного код. Подумайте над этим)))
                              0
                              Конечно. Переделаю
                      +3

                      Удобно, когда на GPIO Raspberry Pi ничего другого не подключено, кроме одной шины с датчиками. Как в мануалах написано подключать к 4 ноге ds18b20, так все и подключают.
                      Пара лет назад мне потребовалось подключить ds18b20, на Raspberry оставались свободные пару ног и как оказалось в ядре захардкожена нога 4 для 1-wire. После пары дней танцов с бубнами, пересборкой модулей ядра я добился того, что 1-wire заработал на 22 ноге.
                      Сейчас по прежнему по умолчанию нога для 1-wire это 4. Но можно и поменять:


                      pi@raspberrypi:~ $ tail  /boot/config.txt 
                      #dtoverlay=lirc-rpi
                      
                      # Additional overlays and parameters are documented /boot/overlays/README
                      
                      # Enable audio (loads snd_bcm2835)
                      dtparam=audio=on
                      gpu_mem=160
                      dtoverlay=lirc-rpi,gpio_in_pin=11,gpio_out_pin=9
                      dtoverlay=w1-gpio,gpiopin=22
                        0
                        Своего датчика пока нет(но все готово для запуска).

                        Мониторю температуру с чужих
                        http://pastebin.com/7wGGZNtW

                        Only users with full accounts can post comments. Log in, please.