Пытаясь подключить свой датчик температуры 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

# 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#{}#{}\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. Теперь мы можем всё настроить по вкусу (название, тип, местоположение и т.д.). Сделать датчик публичным можно через сутки после начала передачи показаний.

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

До новых встреч :)
Поделиться с друзьями
-->

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


  1. Snowtomcat
    10.02.2017 04:06

    ИМХО в статье на хватает линка на Ваш работающий датчик. Можете опубликовать?


    1. nikitos_2002
      10.02.2017 04:07

      Попробую. Сейчас зима, теплица работает с перебоями.


  1. DARK-ADMIN
    10.02.2017 04:06

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


    1. chelaxe
      10.02.2017 20:53

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


  1. general2201
    10.02.2017 04:06
    -1

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


    1. nikitos_2002
      10.02.2017 04:07
      +1

      На таком языке нашёл я все примеры.


      1. general2201
        10.02.2017 04:16

        А, ну в таком случае ничего не имею против


    1. LumberJack
      10.02.2017 09:35
      +2

      В Raspbian-e он есть по умолчанию. Меньше проблем, никаких левых библиотек качать не нужно. Так что выбор вполне оправдан.


      1. Ungla
        10.02.2017 14:23

        Python3 там так же есть, все «DIY»-библиотеки для третьего питона есть, синтаксис у них лучше и они быстрее. Так что выбор оправдан только тем, что автор не нашёл ничего другого. Я не чтобы поогрызаться, а к тому что Python3 уже всюду предпочтительнее.


  1. teleghost
    10.02.2017 04:22
    +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), а остальное — уникальный номер устройства. И если Вы свои устройства зашиваете в скрипт хардкодом, предупредите, пожалуйста, об этом явно в комментариях. Хотя резиденты местного клуба и так разберутся, но для гостей портала все вышеперечисленное не будет лишним.


    1. nikitos_2002
      10.02.2017 04:31
      +2

      Учту ошибки. Вечером исправлю)


      1. xcore78
        10.02.2017 15:52

        Поправьте заголовок заодно, пожалуйста.


        1. nikitos_2002
          10.02.2017 17:06

          Как именно?


          1. xcore78
            10.02.2017 17:19

            с народнЫМ мониторингОМ (кем/чем)


            1. nikitos_2002
              10.02.2017 18:08

              хорошо


      1. teleghost
        11.02.2017 06:30

        Вам ещё про параметр gpiopin ниже порекомендовали, это к вопросу 1-wire.


  1. AVX
    10.02.2017 09:02
    -1

    Этот датчик разве не может работать как триггер? Насколько помню, что 1820, что 1821 — примерно одного класса устройства. Имел опыт работы с 18С21 (может быть неточно, там ещё что-то было в маркировке) в триггерном режиме. Суть в том, что датчик можно запрограммировать, так, что он перестаёт выдавать по 1-wire температуру, но выход принимает только два значения: лог.1 и лог.0. Запрограммировать верхний предел температуры и нижний можно специальным программатором (например, тут описано http://www.rtcs.ru/article_detail.asp?id=73). Точность в таком случае 1 градус, что для Вашего случая (насколько понял, теплица) вполне подойдёт для автоматической регулировки без каких либо микроконтроллеров и прочего — просто усилитель на транзисторе и реле, управляющее обогревом.
    Конечно, если микроконтроллер/компьютер уже есть, то всё это и на нём можно сделать, я просто хотел сказать, что для регулировки температуры не нужно закупать компьютер.


    1. LumberJack
      10.02.2017 09:36

      А на narodmon что передавать: 0 или 1?


      1. AVX
        10.02.2017 11:00
        +1

        Я просто думал, что датчики ставят как раз с целью автоматизации — чтобы была автоматическая регулировка. Но если нужен именно мониторинг значений температуры — то триггерный режим не подойдёт. Правда, можно передавать 0 или 1 — только трактовать это надо будет так — 1 — превышение TH, 0 — температура ниже TL (или наоборот, инвертировать можно хоть логикой в программе, хоть аппаратно).


    1. Tomasina
      10.02.2017 17:08

      А где об этом режиме почитать?
      Гугл выдает именно эту страницу.


      1. AVX
        11.02.2017 17:31
        +1

        Упс… я поленился почитать подробности в документации. На самом деле: DS1820 — термометр, DS1821 — термостат. Т.е. именно 1820 использовать в таком режиме нельзя, а 1821 — можно.


  1. ta4ukoma
    10.02.2017 14:31

    Может я не так понял — подскажите, а MAC устройства это разве не MAC самой малинки которая данные отправляет? Если да, то почему вы не берете адрес из системы и вбиваете его руками?


    1. nikitos_2002
      10.02.2017 14:33

      Можно и автоматизировать. Просто я обычно не меняю WIFI адаптеры на малинке, так что MAC не меняется. Каждый раз проверять его не нужно.


      1. ta4ukoma
        10.02.2017 14:42

        Я вообще то был уверен что программисты унифицируют код в порядке хорошего тона, чтобы голова не болела о таких мелочах. То есть вот случись чего с вашей малинкой или с wifi адаптером, или кто-то воспользуется вашим скриптом — придётся править этот кусок кода руками. Да банально — вам пришлось лезть в систему и копировать оттуда MAC адрес сетевухи в ручную! Не лень разве было?)


        1. nikitos_2002
          10.02.2017 15:03

          Я думаю, Вы конечно правы. Просто в первую очередь я делал это для себя, и такое не предусмотрел. Добавлю это в статью. Спасибо )


          1. ta4ukoma
            10.02.2017 15:19
            +1

            Опять же) если вы делитесь своим творением с окружающими, то это уже точно не для вас одного код. Подумайте над этим)))


            1. nikitos_2002
              10.02.2017 15:33

              Конечно. Переделаю


  1. aivs
    10.02.2017 15:48
    +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


  1. delvin-fil
    11.02.2017 04:51

    Своего датчика пока нет(но все готово для запуска).

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