В данной статье мы продолжим эксперименты с Wi-Fi модулем ESP8266 и попробуем реализовать опрос датчика CO2 K-30 через MODBUS.

В первой части мы прошили в ESP8266 NodeMCU, подключили DS18b20 и научились отправлять данные о температуре в облако. Попробуем добавить опрос датчика CO2.
Самое интересное реализовать весь функционал в ESP8266 не подключая внешний контроллер

Hardware и подключение
Добавляем к конфигу из предыдущей статьи датчик K-30.
Соединяем UART RX, UART TX и GND у датчика K-30 и ESP8266. Питание у них будет разное.
Сложность заключается в том, что UART у ESP8266 всего один, так что либо консоль и отладка, либо K-30
Внимание! Питание у K-30 5-14В, у ESP8266 — 3.3В.
Я решил данную проблему применив преобразователь 5->3.3В


Программная часть

1) init.lua — практически не изменился
--init.lua
print("Setting up WIFI...")
wifi.setmode(wifi.STATION)
--modify according your wireless router settings
wifi.sta.config("YOUR_SSID","YOUR_PASSWD")
wifi.sta.connect()
tmr.alarm(1, 1000, 1, function() 
	if wifi.sta.getip()== nil then 
		print("IP unavaiable, Waiting...") 
	else 
		tmr.stop(1)
		print("Config done, IP is "..wifi.sta.getip())
		dofile("all.lua")
	end 
end)


2) all.lua — код опроса датчиков и отправки данных на сервер
pin = 6
t = 0

function read(addr, unit)
  ow.setup(pin)
  result = nil
  flag = false
  if(addr == nil) then
    ow.reset_search(pin)
    count = 0
    repeat
      count = count + 1
      addr = ow.search(pin)
      tmr.wdclr()
    until((addr ~= nil) or (count > 100))
    ow.reset_search(pin)
  end
  if(addr == nil) then
    return result
  end
  crc = ow.crc8(string.sub(addr,1,7))
  if (crc == addr:byte(8)) then
    if ((addr:byte(1) == 0x10) or (addr:byte(1) == 0x28)) then
      ow.reset(pin)
      ow.select(pin, addr)
      ow.write(pin, 0x44, 1)
      present = ow.reset(pin)
      ow.select(pin, addr)
      ow.write(pin,0xBE,1)
      data = nil
      data = string.char(ow.read(pin))
      for i = 1, 8 do
        data = data .. string.char(ow.read(pin))
      end
      crc = ow.crc8(string.sub(data,1,8))
      if (crc == data:byte(9)) then

        t = (data:byte(1) + data:byte(2) * 256) * 625

        t = t / 10000
        return t
      end
      tmr.wdclr()
    else
    end
  else
  end
  return result
end



function sendt(t,co,key)
 print("Temp:"..t.." C\n")
conn=net.createConnection(net.TCP, 0) 
conn:on("receive", function(conn, payload) print(payload) end)
conn:connect(80,'184.106.153.149') 
conn:send("GET /update?key="..key.."&field1="..t.."&field2="..co.." HTTP/1.1\r\n") 
conn:send("Host: api.thingspeak.com\r\n") 
conn:send("Accept: */*\r\n") 
conn:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n")
conn:send("\r\n")

conn:on("sent",function(conn)
                    print("Closing connection")
                      conn:close()
                  end)
conn:on("disconnection", function(conn)
                              print("Got disconnection...")
  end)
end


uart.setup(0,9600,8,0,1,0)
uart.on("data", 0, 
    function(data)
	--print("receive from uart:", data)
		if string.len(data) == 7 then
			result = string.byte(data,4)*256 + string.byte(data,5)
			print (result)
			sendt(t,result,"YOUR_KEY")
		end
    end, 0)


function sendData()
t = read()
uart.write(0,0xFE,0x04,0x00,0x03,0x00,0x01,0xD5,0xC5)
end

tmr.alarm(0, 60000, 1, function() sendData() end )
 


Алгоритм работы:
  • Инициализируем UART на 9600
  • Устанавливаем callback на получение данных из UART. В случае получения пакета из 7 байт(ответ K-30 по MODBUS) отправляем данные на thingspeak.com
  • Каждую минуту опрашиваем датчик температуры DS18b20 и отправляем в UART запрос данных по CO2. Запрос найден в даташите

Раскидать по отдельным файлам не получилось, не хватало памяти, поэтому реализовал как смог. Lua для меня до сих пор тёмный лес.

Результаты


Получилось очень интересное устройство. Питание сделал от USB, соответственно можно брать куда угодно. PowerBank сегодня есть почти у каждого. По поводу Wi-Fi — поднимаем точку на телефоне и наш датчик снова в сети.

По ощущениям — действительно появляется дискомфорт при превышении CO2 уровня в 800-1000 ppm.

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


  1. Meklon
    17.05.2015 19:29

    Вопрос по питанию. Можно ли было просто взять линейный стабилизатор напряжения LM7803 и пару конденсаторов?


    1. ssh1 Автор
      17.05.2015 19:32

      Не пробовал. Он дает 3V, а это нижняя граница для ESP8266 (судя по даташиту 3.0-3.6V).


    1. imwode
      17.05.2015 20:44

      Лучше LM7833, главное не 78_l_33.


      1. Meklon
        17.05.2015 21:52

        А чем лучше? Для меня это актуально.


        1. imwode
          17.05.2015 22:12

          У меня на 3.12В барахлит, на форумах тоже пописывают что к питанию сильно чувствителен модуль. Мож и не в этом проблема…
          Попробовать просто же, ничего не сгорит на 3В


  1. jcmvbkbc
    17.05.2015 20:57

    Сложность заключается в том, что UART у ESP8266 всего один

    Полтора (на втором доступен только TX), а если не использовать SPI-Flash то два.
    Второй находится по адресу 0x60000F00 и его TX торчит из GPIO2.


    1. imwode
      17.05.2015 23:30

      А что делать вот с этим «находится по адресу»? А то мне тут надо было инвертнуть уарт, но так и не понял как к регистрам получить доступ, пришлось транзистором инвертировать.


      1. jcmvbkbc
        18.05.2015 01:03
        +1

        так и не понял как к регистрам получить доступ

        С SDK идут примеры, открываете какой-нибудь examples/IoT_Demo/driver/uart.c и видите что-то такое:
            WRITE_PERI_REG(UART_CONF0(uart_no),    UartDev.exist_parity
                           | UartDev.parity
                           | (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
                           | (UartDev.data_bits << UART_BIT_NUM_S));
        

        Определения этих макросов — в include/eahle_soc.h и examples/IoT_Demo/include/driver/uart_register.h, это обычная запись в MMIO.


        1. imwode
          20.05.2015 03:28
          +1

          Хо хо, работает
          Только почему-то в uart_register.h ошибка, там бит инверсии прописан как 12-й. А вот тут как 22-й, и это правильно

          uart_init(BIT_RATE_9600, BIT_RATE_9600);
          SET_PERI_REG_MASK(UART_CONF0(0), BIT(22));
          


          1. jcmvbkbc
            20.05.2015 04:18

            Хо хо, работает

            Поздравляю (:
            Только почему-то в uart_register.h ошибка

            Я не сильно удивлён; конечно лучше сверяться с документацией.


  1. dannote
    18.05.2015 02:35

    data = nil
    data = string.char(ow.read(pin))
    for i = 1, 8 do
       data = data .. string.char(ow.read(pin))
    end
    crc = ow.crc8(string.sub(data,1,8))
    


    Все же лучше так:

    local data = {}
    for i = 1, 8 do
       table.insert(data, ow.read(pin))
    end
    local crc = ow.crc8(table.concat(data))
    


    1. Klukonin
      18.05.2015 07:56

      Я как-то все не могу уловить смысл использования локальных переменных и функций.
      Так быстрее? Или это в целях экономии памяти?


  1. ignat99
    18.05.2015 10:08
    +1

    harizanov.com/wiki/wiki-home/three-channel-wifi-relaythermostat-board

    Воот это, вероятно, очень хороший проект. Всё реализовано на ESP8266.


  1. ignat99
    18.05.2015 10:41

    www.artik.io/developer — Однако, новое поколение. Можно сделать регистрацию себе и получить устройство.


  1. eschava
    18.05.2015 17:58

    Сколько мА потребляет вся эта конструкция? Я так понимаю, что датчик CO2 находится во включенном состоянии все время?


    1. ssh1 Автор
      18.05.2015 20:31

      На всех измерителях тока для USB пишет 0 мA(до 10), иногда мигает 50 — 100 ма Получается что жрет только ESP8266.
      Работает двое суток от PowerBank емкостью ~ 5000 mAh, сожрал пока 35%.