CO₂ - (, NDIR- ).
, , .

, —
,
(
) . , , , .
, : CO₂ WiFi ESP8266.
► WiFi Inside
:

4 :

, . ( ):

— , , :

4 :

, , . : V (voltage) — , D(data) — , (clock) — , G(ground) — .
G, GND, «» — , (, V) . , G — «», V — «», . … , «» .
, clock, , — , , ( D).
( UART/RS-232), , (=) ( 1200, 9600, 115200 ), , , , .
( , ), — . , , , .
:

, :

, . , - , « » .
ESP8266:

UART ( , , ) .

►
Arduino c ESP8266( ,
). , , , esp8266.ru.
: ,
fedorro, ,
.
,,
CO2_meter.ino:
#define PIN_CLOCK 14
#define PIN_DATA 12
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "mt8060_decoder.h"
const char* ssid = "MikroTik-951";
const char* password = "FAKEPASSWORD";
String co2_value = "";
String tmp_value = "";
String hum_value = "";
int error_count = 0;
ESP8266WebServer server(80);
void setup()
{
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("WiFi connected, IP ");
Serial.println(WiFi.localIP());
server.on("/co2", co2_show);
server.on("/tmp", tmp_show);
server.on("/hum", hum_show);
server.on("/json", json_show);
server.onNotFound(NotFound_show);
server.begin();
pinMode(PIN_CLOCK, INPUT);
pinMode(PIN_DATA, INPUT);
attachInterrupt(digitalPinToInterrupt(PIN_CLOCK), interrupt, FALLING);
}
void interrupt()
{
bool dataBit = (digitalRead(PIN_DATA) == HIGH);
unsigned long ms = millis();
mt8060_message* message = mt8060_process(ms, dataBit);
if (message) {
if (!message->checksumIsValid)
{
error_count++;
}
else
{
switch (message->type)
{
case HUMIDITY:
hum_value = String((double)message->value / 100, 0);
Serial.print("HUM:");
Serial.println(hum_value);
break;
case TEMPERATURE:
tmp_value = String((double)message->value / 16 - 273.15, 1);
Serial.print("TMP:");
Serial.println(tmp_value);
break;
case CO2_PPM:
co2_value = String(message->value, DEC);
Serial.print("CO2:");
Serial.println(co2_value);
break;
default:
break;
}
}
}
}
void co2_show() {
server.send(200, "text/plain", co2_value);
}
void tmp_show() {
server.send(200, "text/plain", tmp_value);
}
void hum_show() {
server.send(200, "text/plain", hum_value);
}
void NotFound_show() {
String form = "<!DOCTYPE html><html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\"><title>Dadget 8060 CO₂ monitor</title><style>.c{text-align: center;} div,input{padding:5px;font-size:1em;} input{width:95%;} body{text-align: center;font-family:verdana;} button{border:0;border-radius:0.3rem;background-color:#1fa3ec;color:#fff;line-height:2.4rem;font-size:1.2rem;width:100%;} .q{float: right;width: 64px;text-align: right;}</style><style type=\"text/css\"></style></head><body><div style=\"text-align:left;display:inline-block;min-width:260px;\"><h1>Dadget 8060 CO₂ monitor</h1><form action=\"/co2\" method=\"get\"><button>CO₂ value ([co2] ppm now)</button></form><br><form action=\"/tmp\" method=\"get\"><button>Temperature value ([tmp]° now)</button></form><br><form action=\"/hum\" method=\"get\"><button>Humidity value ([hum]% now)</button></form><br><form action=\"/json\" method=\"post\"><button>JSON(all values)</button></form></div></body></html>";
form.replace("[co2]", co2_value);
form.replace("[hum]", hum_value);
form.replace("[tmp]", tmp_value);
server.send(200, "text/html", form);
}
void json_show() {
String json = "[{\"co2\":";
json += co2_value;
json += ",\"tmp\":";
json += tmp_value;
json += ",\"hum\":";
json += hum_value;
json += ",\"serial\":";
json += ESP.getChipId();
json += ",\"errors\":";
json += error_count;
json += ",\"uptime_min\":";
json += String(millis()/60000);
json += "}]";
server.send(200, "application/json", json);
}
void loop()
{
server.handleClient();
}
,
mt8060_decoder.cpp:
#include "mt8060_decoder.h"
#define MT8060_MAX_MS 2
#define MT8060_MSG_LEN 5
#define MT8060_MSG_TYPE_BYTE_IDX 0
#define MT8060_MSG_VAL_HIGH_BYTE_IDX 1
#define MT8060_MSG_VAL_LOW_BYTE_IDX 2
#define MT8060_MSG_CHECKSUM_BYTE_IDX 3
#define MT8060_MSG_CR_BYTE_IDX 4
#define BITS_IN_BYTE 8
static uint8_t buffer[MT8060_MSG_LEN];
static int num_bits = 0;
static unsigned long prev_ms;
static mt8060_message _msg;
static mt8060_message *msg = &_msg;
void mt8060_decode(void)
{
uint8_t checksum = buffer[MT8060_MSG_TYPE_BYTE_IDX] + buffer[MT8060_MSG_VAL_HIGH_BYTE_IDX] + buffer[MT8060_MSG_VAL_LOW_BYTE_IDX];
msg->checksumIsValid = (checksum == buffer[MT8060_MSG_CHECKSUM_BYTE_IDX] && buffer[MT8060_MSG_CR_BYTE_IDX] == 0xD);
if (!msg->checksumIsValid) {
return;
}
msg->type = (dataType)buffer[MT8060_MSG_TYPE_BYTE_IDX];
msg->value = buffer[MT8060_MSG_VAL_HIGH_BYTE_IDX] << BITS_IN_BYTE | buffer[MT8060_MSG_VAL_LOW_BYTE_IDX];
}
mt8060_message* mt8060_process(unsigned long ms, bool data)
{
if ((ms - prev_ms) > MT8060_MAX_MS) {
num_bits = 0;
}
prev_ms = ms;
if (num_bits < MT8060_MSG_LEN * BITS_IN_BYTE) {
int idx = num_bits / BITS_IN_BYTE;
buffer[idx] = (buffer[idx] << 1) | (data ? 1 : 0);
num_bits++;
if (num_bits == MT8060_MSG_LEN * BITS_IN_BYTE) {
mt8060_decode();
return msg;
}
}
return nullptr;
}
,
mt8060_decoder.h
#include <stdint.h>
#include <stdbool.h>
typedef enum
{
HUMIDITY = 0x41,
TEMPERATURE = 0x42,
CO2_PPM = 0x50,
} dataType;
typedef struct {
dataType type;
uint16_t value;
bool checksumIsValid;
} mt8060_message;
mt8060_message* mt8060_process(unsigned long ms, bool data);
,
GitHub. - , , !
, …

! , :

, , ,
( ), :

►
, « » « -» . , - , .
, ESP, , , - WiFi-… , ,
.
, , Logic Machine — . , , , .
Sheduled-( ), :

- :
local http = require('http')
local json = require('json')
local raw_data, code = socket.http.request('http://co2meter.lc/json')
if (code == 200) then
local data = json.decode(raw_data)
if (data ~= nil) then
if (data[1].uptime_min > 2) then
grp.update('S_CO2_CO2', data[1].co2)
grp.update('S_CO2_TMP', data[1].tmp)
grp.update('S_CO2_HUM', data[1].hum)
end
end
end
! :

. ( Dadget , )! Trends logs —> Add new trend log:

- , , :

, :

, CO₂ !
№1: CO₂.
№2: - ( ) CO₂ .
№3: ( ) . ( ) , .
№4: CO₂, , . , .
№5: CO₂, , . .

►
, CO₂,
. ( , ), CO₂. LM :
Event-based( ), , CO₂:

, 1000ppm, 800, - :
value = grp.getvalue("S_CO2_CO2")
if (value > 1000) then
grp.write('HP-7.1', true)
elseif (value < 800) then
grp.write('HP-7.1', false)
end
, CO₂ 1000ppm, , 800ppm.
!

:
Arduino, :
telegram.me/IOTandSmarthome14 , ,
« » 10%- , GEEKT-MK.