MYSENSORS Zählermodul für Gaszähler API 2.0

Gaszähler mit Impulsgeber

Hier schon einmal der Sketch. Mit ihm erzeuge ich die Zählimpulse in MYSENSORS. In FHEM verwende ich dann das Modul Gascalculator zur weiteren Berechnung. Als Kontakt verwende ich einen einfach Reedkontakt.

/**
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2015 Sensnology AB
 * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 *******************************
 *
 * DESCRIPTION
 *
 * Simple binary switch example 
 * Connect button or door/window reed switch between 
 * digitial I/O pin 3 (BUTTON_PIN below) and GND.
 * http://www.mysensors.org/build/binary
 */
#define MY_RADIO_NRF24

#include <MySensors.h>
#include <SPI.h>
#include <Bounce2.h>

#define CHILD_ID 3
#define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch

 Bounce debouncer = Bounce(); 
int oldValue=-1;

// Change to V_LIGHT if you use S_LIGHT in presentation below
MyMessage msg(CHILD_ID,V_TRIPPED);

void setup()  
{  

  
  // Setup the button
  pinMode(BUTTON_PIN,INPUT);
  // Activate internal pull-up
  digitalWrite(BUTTON_PIN,HIGH);
  
  // After setting up the button, setup debouncer
  debouncer.attach(BUTTON_PIN);
  debouncer.interval(5);
}
void presentation(){
sendSketchInfo("DOOR", "v0.1");
  // Register binary input sensor to gw (they will be created as child devices)
  // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. 
  // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
 present(CHILD_ID, S_DOOR);  
}


//  Check if digital input has changed and send in new value
void loop() 
{
 
  debouncer.update();
  // Get the update value
  int value = debouncer.read();
 
  if (value != oldValue) {
     // Send in the new value
     send(msg.set(value==HIGH ? 1 : 0));
     oldValue = value;
  }
} 

https://smarthome.gleisnetze.de

MQ135.h Beispiel Sketch zum Verstehen der Bibliothek für die CO2 Messung

5sens Modul

Anbei ein kleiner Sketch zum Verstehen des Bibliothek vom G. Krocker zur Anzeige der relevanten Werte des MQ135 und Verwendung der Temperatur-Kompensation. Der MQ135 Sensor wird verwendet um die Luftgüte, hier speziell das CO2 zu messen. Mit den Werten ist eine Eichung des Sensors auf den mittleren CO2 Wert in der Atmosphäre (ca. 400 ppm) möglich (rzeroc). Einen kompletten Sketch findet man hier Vier Sensoren Sketch

Hilfreich:

https://www.grower.ch/forum/threads/wir-basteln-ein-arduino-co2-messgeraet.89083/

https://hackaday.io/project/3475-sniffing-trinket

 

#include "MQ135.h"
#include <DHT.h>  

#define HUMIDITY_SENSOR_DIGITAL_PIN 4 // DHT22 an PIN4

MQ135 gasSensor = MQ135(0); //GAS Sensor PIN A0

DHT dht;



void setup() {
   Serial.begin(115200);
    dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
    
}

void loop() {
{
  float h = dht.getHumidity();
  float t = dht.getTemperature();
 
  float rzero = gasSensor.getRZero();
  float rzeroc = gasSensor.getCorrectedRZero( t, h);
   
  float ppm = gasSensor.getPPM();
  float ppmc = gasSensor.getCorrectedPPM(t, h);
 
  Serial.println(t);
  Serial.println(h);   
  Serial.println(rzero);
  Serial.println(rzeroc);
  Serial.println(ppm);
  Serial.println(ppmc);
  Serial.println();

  delay(3000);
 
}
}

 

 

Gasverbrauch messen mit Arduino FHEM und MYSENSORS ohne Raspberry

Gaszähler mit Impulsgeber

Leider gibt es keine fertige Lösung obwohl es einfach scheint. Bisher habe ich nur Ergebnisse mit Firmata für Raspberry und Netzwerkschnittstelle gefunden. Das ist mir zu aufwändig. Es gibt für Arduino mysensors Sketche, die die Türkontakte (Reedkontakte) erkennen. Die Reedkontakte lassen sich am Zähler anbringen und reagieren auf den magnetischen Punkt am Zahlenrad. Das wäre der Hardware-Ansatz. Also muss ich mich bei Gelegenheit an die Software machen.

Smarthome Arduino MYSENSORS FHEM Sketch CO2 Bewegung Temperatur Feuchte

FHEM Abbildung Sensoren Feuchte Temp CO2 Bewegung

Allegmein

Der Sketch stammt von Karl-Heinz Wind und wurde von mir angepasst. Er enthält die Berechnung und Anzeige der Sensoren für CO2 (MQ135), Feuchte, Temperatur und Bewegung. Es wurden ausschließlich typische MYSENSORS-Bauteile verwendet. Sollten bestimmte Bibliotheken fehlen, kann ich die gerne noch bereitstellen.

 

Sketch

#include <SPI.h>
#include <MySensor.h>

#include <Wire.h>

#include <DHT.h>
#include <MQ135.h>

#include „Timer.h“

//—————————————————————————-
//unsigned long SLEEP_TIME = 10000; //Sleep time between reports (in milliseconds)
#define DIGITAL_INPUT_SENSOR 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
#define INTERRUPT DIGITAL_INPUT_SENSOR-3 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define CHILD_ID 1   // Id of the sensor child

//—————————————————————————–
// Timer
Timer timer;
#define TEMP_UPDATE_INTERVAL 30000

//—————————————————————————–
// DHT22
#define CHILD_ID_TEMP 2
#define CHILD_ID_HUM 3
#define HUMIDITY_SENSOR_DIGITAL_PIN 4

DHT dht;
float lastTemp;
float lastHum;
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);

//—————————————————————————–
// MQ135
#define CHILD_ID_CO2_CORRECTED 0
#define CHILD_ID_CO2 1
#define CHILD_ID_R0 4
#define CO2_SENSOR_ANALOG_PIN 0
#define CO2_SENSOR_BUFFER_SIZE 3

/// Calibration resistance at atmospheric CO2 level
// Buero 21Grad Regen
#define RZERO 300.0
#define EEPROM_R0 0

MQ135 gasSensor = MQ135(CO2_SENSOR_ANALOG_PIN, RZERO);
int lastC02;
int lastCO2Corrected;
float lastR0;

//RunningAverage lastCO2Values(CO2_SENSOR_BUFFER_SIZE);

//—————————————————————————–
// MySensor
MySensor gw;
MyMessage msgCO2Corrected(CHILD_ID_CO2_CORRECTED, V_VAR1);
MyMessage msgCO2(CHILD_ID_CO2, V_VAR1);
MyMessage msgR0(CHILD_ID_R0, V_VAR1);
MyMessage msg(CHILD_ID, V_TRIPPED);

//—————————————————————————–
void setup()
{
Serial.begin(115200);
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);

gw.begin(incomingMessage, AUTO, true);
gw.sendSketchInfo(„CO2 Sensor MQ-135“, „1.3“);
gw.present(CHILD_ID_CO2_CORRECTED, S_AIR_QUALITY);
gw.present(CHILD_ID_CO2, S_AIR_QUALITY);
gw.present(CHILD_ID_TEMP, S_TEMP);
gw.present(CHILD_ID_HUM, S_HUM);
gw.present(CHILD_ID_R0, S_CUSTOM);

gw.sendSketchInfo(„Motion Sensor“, „1.0“);
pinMode(DIGITAL_INPUT_SENSOR, INPUT);
gw.present(CHILD_ID, S_MOTION);

uint8_t R02 = gw.loadState(EEPROM_R0);

// get R0 from EEPROM
float R0 = R02 * 2;
if (R0 > 1.0 && R0 < 400.0)
{
Serial.print(F(„Setting R0 from EEPROM: „));
}
else
{
Serial.print(F(„Setting default R0: „));
R0 = RZERO;
}

Serial.print(R0);
Serial.println(F(„“));

gasSensor.setR0(R0);
//float ppm = gasSensor.getPPM();
//lastCO2Values.fillValue(ppm, CO2_SENSOR_BUFFER_SIZE);

//int tickEvent1 =
timer.every(TEMP_UPDATE_INTERVAL, timerHandler);

}

bool DHT22Changed(bool waitMinimumSamplingPeriod = true)
{
bool changed = false;

if (waitMinimumSamplingPeriod)
{
delay(dht.getMinimumSamplingPeriod());
}

float temperature = dht.getTemperature();
if (isnan(temperature))
{
Serial.println(F(„Failed reading temperature from DHT“));
}
else if (temperature != lastTemp)
{
lastTemp = temperature;
Serial.print(„T: „);
Serial.println(temperature);
changed = true;
}

float humidity = dht.getHumidity();
if (isnan(humidity))
{
Serial.println(F(„Failed reading humidity from DHT“));
}
else if (humidity != lastHum)
{
lastHum = humidity;
Serial.print(F(„H: „));
Serial.println(humidity);
changed = true;
}

return changed;
}

bool MQ135Changed(float t, float h)
{
bool changed = false;

lastR0 = gasSensor.getRZero();
Serial.print(F(„R0: „));
Serial.println(lastR0);

{
float ppm = gasSensor.getPPM();

Serial.print(F(„CO2 ppm: „));
Serial.print(ppm);

//lastCO2Values.addValue(ppm);
//ppm = lastCO2Values.getAverage();

//Serial.print(“ average: „);
//Serial.print(ppm);

int roundedPpm = (int)ppm;
Serial.print(F(“ –> „));
Serial.println(roundedPpm);

if (roundedPpm != lastC02)
{
lastC02 = roundedPpm;
changed = true;
}
}

{
float ppm = gasSensor.getCorrectedPPM(t, h);

Serial.print(F(„CO2 corrected ppm: „));
Serial.print(ppm);

int roundedPpm = (int)ppm;
Serial.print(F(“ –> „));
Serial.println(roundedPpm);

if (roundedPpm != lastCO2Corrected)
{
lastCO2Corrected = roundedPpm;
changed = true;
}
}
// Read digital motion value
boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;

Serial.println(tripped);
gw.send(msg.set(tripped?“1″:“0“));  // Send tripped value to gw

// Sleep until interrupt comes in on motion sensor. Send update every two minute.
//gw.sleep(INTERRUPT,CHANGE, SLEEP_TIME);

return changed;
}

void timerHandler()
{
bool humidityChanged = DHT22Changed(false);
bool airQualityChanged = MQ135Changed(lastTemp, lastHum);

if (humidityChanged || airQualityChanged)
{
gw.send(msgTemp.set(lastTemp, 1));
gw.send(msgHum.set(lastHum, 1));
gw.send(msgCO2Corrected.set(lastCO2Corrected));
gw.send(msgCO2.set(lastC02));
gw.send(msgR0.set(lastR0, 2));
}
}

void loop()
{
gw.process();

timer.update();

}

void incomingMessage(const MyMessage& message)
{
Serial.println(F(„Incoming Message:“));

if (message.isAck())
{
Serial.println(F(„This is an ack from gateway“));
}

uint8_t sensor = message.sensor;
if (sensor == CHILD_ID_R0)
{
float R0 = message.getFloat();

Serial.print(F(„Incoming R0: „));
Serial.print(R0);
Serial.println(F(„“));

gw.saveState(EEPROM_R0, (uint8_t)(R0/2));
gasSensor.setR0(R0);
gw.send(msgR0.set(R0, 2));
}
}

Sensor (Multi) für MYSENSORS FHEM SMARTHOME ARDUINO

Sensor Raumluftgüte CO2 Programm
Sensor Programm Raumluftgüte CO2 mit FHEM MYSENSORS MQ135.h
Fertiges Sensor-Modul
Fertiges Sensor-Modul (Verdrahtung Unterseite), Raumluft (CO2), Motion, Temperatur und Feuchte

1. Sensor – Modul als Ziel

Ergebnis ist ein Sensor-Modul für CO2 (Luftgüte), Temperatur, Feuchtigkeit und Anwesenheit/Bewegung für Wohnräume. Per MYSENSORS werden die Bauteile ausgelesen und in FHEM als Smarthome–System integriert um verschiedenste Darstellungs- und Weiterverwendungen als Sensoren/Aktoren zu ermöglichen.

Außerdem wird der Temperatureinfluss auf den CO2-Wert kompensiert.

2. Sensor – Modul im Detail

  • MQ135 (Raumluftgüte/CO2 – Sensor)
  • Dallas DS18b20+ (Temperatur – Sensor)
  • DHT11 (Luftfeuchte – Sensor)
  • HC-SR501 (IR-Bewegungs – Sensor)
  • Spannungswandler
  • Netztteil

Einziges Problem ist im Moment, dass der DALLAS Temperatur – Sensor auf der Lochraster-Platine falsche Werte lieferte. Das lag sicher daran, dass der Spannungswandler und die Heizung des CO2-Sensors Wärme erzeugen. Als Abhilfe habe ich den Sensor mit Drähten an der Platine eingelötet. Scheinbar überträgt sich die Wärme zu stark über die Leiterbahnen.

3. Sensor – Sketche

3.1 Dank für die Sensor – Sketch-Grundlagen

Dank gilt den Vorarbeitern, die die Grundlagen für den Gesamtsketch der Sensor en erstellt haben:

  • GeorgK MQ135 Sensor – Bibliothek
  • Heinz auf MYSENSORS.ORG
  • Epierre auf MYSENSORS.ORG
  • et. al.

3.2 Sensor-Sketch Anmerkungen

Meine Arbeit liegt in der Zusammenführung der einzelnen Sketche für die Sensor-Unterstützung und deren Anpassung. Da ich Anfänger beim Programmieren bin ist mir der Einstieg doch gelungen, weil ich relativ grob arbeiten konnte – weil ich hauptsächlich die Einzelzeilen ineinander schieben und dadurch sehr schnell Ergebnisse testen konnte.

Der Code ist auf Grund meiner Anfängerschaft sicher etwas wirr. Ich werde bei Gelegenheit den Code bereinigen und veröffentlichen. Sorry dafür

//ACHTUNG DER CODE IST NICHT FEHLERFREI BZW. AUF NICHT AUF DEM AKTUELLEN STAND. 
//ÄNDERUNGEN FOLGEN


#include <SPI.h>
#include <MySensor.h>
#include <Wire.h>

//#include "RunningAverage.h"

#include <DHT.h>
#include <MQ135.h>

#include "Timer.h"
#include <DallasTemperature.h>
#include <OneWire.h>

//--------------------------------------------------------------------
// DALLAS

#define ONE_WIRE_BUS 5 // Pin where dallase sensor is connected
#define MAX_ATTACHED_DS18B20 16

unsigned long SLEEP_TIME = 10000; // Sleep time between reads (in milliseconds)
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// MySensor gw;
float lastTemperature[MAX_ATTACHED_DS18B20];
int numSensors=0;
boolean receivedConfig = false;
boolean metric = true;
// Initialize temperature message
MyMessage msg(0,V_TEMP);
float temperature;
//--------------------------------------------------------------------
// Timer
Timer timer;
#define TEMP_UPDATE_INTERVAL 1000

//--------------------------------------------------------------------
// DHT22
#define CHILD_ID_TEMP 2
#define CHILD_ID_HUM 3
#define HUMIDITY_SENSOR_DIGITAL_PIN 3

DHT dht;
float lastTemp;
float lastHum;
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);

//--------------------------------------------------------------------
// MQ135
#define CHILD_ID_CO2_CORRECTED 0
#define CHILD_ID_CO2 1
#define CHILD_ID_R0 4
#define CO2_SENSOR_ANALOG_PIN 0
#define CO2_SENSOR_BUFFER_SIZE 3

/// Calibration resistance at atmospheric CO2 level
// Buero 21Grad Regen
#define RZERO 300.0
#define EEPROM_R0 0

MQ135 gasSensor = MQ135(CO2_SENSOR_ANALOG_PIN, RZERO);
int lastC02;
int lastCO2Corrected;
float lastR0;

//RunningAverage lastCO2Values(CO2_SENSOR_BUFFER_SIZE);

//--------------------------------------------------------------------
// MySensor
MySensor gw;
MyMessage msgCO2Corrected(CHILD_ID_CO2_CORRECTED, V_VAR1);
MyMessage msgCO2(CHILD_ID_CO2, V_VAR1);
MyMessage msgR0(CHILD_ID_R0, V_VAR1);

//--------------------------------------------------------------------
void setup()
{
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);

gw.begin(incomingMessage, AUTO, true);
gw.sendSketchInfo("CO2 Sensor MQ-135", "1.3");
gw.present(CHILD_ID_CO2_CORRECTED, S_AIR_QUALITY);
gw.present(CHILD_ID_CO2, S_AIR_QUALITY);
gw.present(CHILD_ID_TEMP, S_TEMP);
gw.present(CHILD_ID_HUM, S_HUM);
gw.present(CHILD_ID_R0, S_CUSTOM);

// Startup OneWire
sensors.begin();

// Startup and initialize MySensors library. Set callback for incoming messages.
gw.begin();
// For static ID's at the beginning, you can do the following (4 being the sensor node id):
// gw.begin(NULL,4,false);

// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo("Temperature Sensor", "1.0");

// Fetch the number of attached temperature sensors
numSensors = sensors.getDeviceCount();

// Present all sensors to controller
for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
gw.present(i, S_TEMP);

}

//float R0 = gw.loadState(EEPROM_R0);

int R0 = 600;

Serial.print(F("Setting R0 from EEPROM: "));

Serial.print(R0);
Serial.println(F(""));

gasSensor.setR0(R0);
// float ppm = gasSensor.getPPM();
//lastCO2Values.fillValue(ppm, CO2_SENSOR_BUFFER_SIZE);

//int tickEvent1 =
timer.every(TEMP_UPDATE_INTERVAL, timerHandler);
//int tickeEvent2 =
//timer.every(PRESSURE_UPDATE_INTERVAL, pressureTimerHandler);

}

bool DHT22Changed(bool waitMinimumSamplingPeriod = true)
{
bool changed = false;

if (waitMinimumSamplingPeriod)
{
delay(dht.getMinimumSamplingPeriod());
}

//  float temperature = dht.getTemperature();
// if (isnan(temperature))
// {
//    Serial.println(F("Failed reading temperature from DHT"));
//}
//else if (temperature != lastTemp)
//{

// changed = true;
//}

float humidity = dht.getHumidity();
if (isnan(humidity))
{
Serial.println(F("Failed reading humidity from DHT"));
}
else if (humidity != lastHum)
{
lastHum = humidity;
Serial.print(F("H: "));
Serial.println(humidity);
changed = true;
}

return changed;
}

bool MQ135Changed(float t, float h)
{

bool changed = false;

lastR0 = gasSensor.getRZero();
Serial.print(F("R0: "));
Serial.println(lastR0);

{
float ppm = gasSensor.getPPM();

Serial.print(F("CO2 ppm: "));
Serial.print(ppm);

//lastCO2Values.addValue(ppm);
//ppm = lastCO2Values.getAverage();

//Serial.print(" average: ");
//Serial.print(ppm);

int roundedPpm = (int)ppm;
// Serial.print(F(" --> "));
Serial.println(roundedPpm);

if (roundedPpm != lastC02)
{
lastC02 = roundedPpm;
changed = true;
}

}

{

float ppm = gasSensor.getCorrectedPPM(t, h);
Serial.print(F("CO2 corrected ppm: "));
Serial.print(ppm);

int roundedPpm = (int)ppm;
Serial.print(F(" --> "));
Serial.println(roundedPpm);

if (roundedPpm != lastCO2Corrected)
{
lastCO2Corrected = roundedPpm;
changed = true;
}

// Grundwert CO2 > 400 ppm,
if (lastCO2Corrected < 400)
{
float R0 = lastR0;
gasSensor.setR0(R0);
Serial.print(F("CO2 < 600 --> R0 gesetzt "));

Serial.print(R0);
Serial.println(F(""));

//    gw.saveState(EEPROM_R0,(float)(R0));

}
return changed;
}

}

void timerHandler()
{
bool humidityChanged = DHT22Changed(false);
bool airQualityChanged = MQ135Changed(lastTemp, lastHum);

if (humidityChanged || airQualityChanged)
{
gw.send(msgTemp.set(lastTemp, 1));
gw.send(msgHum.set(lastHum, 1));
gw.send(msgCO2Corrected.set(lastCO2Corrected));
gw.send(msgCO2.set(lastC02));
gw.send(msgR0.set(lastR0, 2));
}
}

//-------------------------------------------------------------

void loop()
{

gw.process();

timer.update();

// Fetch temperatures from Dallas sensors-----------------------------------------------------

sensors.requestTemperatures();

// Read temperatures and send them to controller
for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {

// Fetch and round temperature to one decimal
float temperature = static_cast<float>(static_cast<int>((gw.getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;

// Only send data if temperature has changed and no error
if (lastTemperature[i] != temperature && temperature != -127.00) {

// Send in the new temperature
gw.send(msg.setSensor(i).set(temperature,1));
lastTemperature[i]=temperature;
float lastTemperature=temperature;
Serial.print(F("Auslesung Werte "));
//Serial.print(lastTemperature[i]);
Serial.print(lastTemperature);

}
}

gw.sleep(SLEEP_TIME);
}

void incomingMessage(const MyMessage& message)
{
Serial.println(F("Incoming Message:"));

if (message.isAck())
{
Serial.println(F("This is an ack from gateway"));
}

uint8_t sensor = message.sensor;
if (sensor == CHILD_ID_R0)
{
float R0 = message.getFloat();

Serial.print(F("Incoming R0: "));
Serial.print(R0);
Serial.println(F(""));

//  gw.saveState(EEPROM_R0, (int)(R0));
gasSensor.setR0(R0);
gw.send(msgR0.set(R0, 2));
}
}