Meterkast/Meterkast.ino
2021-12-30 13:22:20 +01:00

320 lines
9.0 KiB
C++

// Use this sensor to measure KWH and Watt of your house meeter
// You need to set the correct pulsefactor of your meeter (blinks per KWH).
// The sensor starts by fetching current KWH value from gateway.
// Reports both KWH and Watt back to gateway.
//
// Unfortunately millis() won't increment when the Arduino is in
// sleepmode. So we cannot make this sensor sleep if we also want
// to calculate/report watt-number.
// Enable debug prints to serial monitor
#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_NRF24
//#include <SPI.h>
#include <MySensors.h>
#include <Bounce2.h>
#define P_DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!)
#define P_INTERRUPT P_DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
#define W_DIGITAL_INPUT_SENSOR 4 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
//#define P_PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter
#define W_PULSE_FACTOR 2000 // Nummber of blinks per m3 of your meter (One rotation/liter)
#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false.
//#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers.
#define W_MAX_FLOW 40 // Max flow (l/min) value to report. This filters outliers.
//#define P_CHILD_ID 1 // Id of the sensor child
#define W_CHILD_ID 2 // Id of the sensor child
//unsigned long P_SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
unsigned long W_SEND_FREQUENCY = 60000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
//Deurbel
unsigned long T_DEURBEL_ON = 700;
unsigned long t_deurbel;
boolean deurbel_on = false;
boolean Bel_Disabled = false;
//MySensor gw;
boolean W_pcReceived = false;
double W_ppl = ((double)W_PULSE_FACTOR)/1000; // Pulses per liter
volatile unsigned long W_pulseCount = 0;
volatile unsigned long W_lastBlink = 0;
volatile double W_flow = 0;
unsigned long W_oldPulseCount = 0;
unsigned long W_newBlink = 0;
double W_oldflow = 0;
double W_volume =0;
double W_oldvolume =0;
unsigned long W_lastPulse =0;
boolean W_puls = false;
boolean W_prevpuls = false;
unsigned long W_lastSend;
MyMessage flowMsg(W_CHILD_ID,V_FLOW);
MyMessage volumeMsg(W_CHILD_ID,V_VOLUME);
MyMessage lastCounterMsg(W_CHILD_ID,V_VAR1);
//Deur en deurbel
#define d1_BUTTON_PIN 5 // Arduino Digital I/O pin for button/reed switch voordeur
#define d2_BUTTON_PIN 6 // Arduino Digital I/O pin for button/reed switch deurbel drukker
#define d1_CHILD_ID 11 // Id voordeur contact
#define d2_CHILD_ID 12 // Id deurbel drukker
#define O_DEURBEL_PIN 7 // Output relais deurbel
#define O_BUZZER_PIN 8 // Output buzzer
#define BEL_CHILD_ID 12 // ID deurbel relais
#define DIS_DEURBEL_CHILD_ID 13 // ID deurbel disable
#define BUZZER_CHILD_ID 99 // ID Buzzer
//Declare deuren
Bounce d1_debouncer = Bounce();
int d1_oldValue=-1;
Bounce d2_debouncer = Bounce();
int d2_oldValue=-1;
MyMessage d1_msg(d1_CHILD_ID,V_TRIPPED);
MyMessage d2_msg(d2_CHILD_ID,V_LIGHT);
MyMessage BEL_msg(BEL_CHILD_ID, V_LIGHT);
MyMessage DIS_DEURBEL_msg(DIS_DEURBEL_CHILD_ID, V_LIGHT);
MyMessage BUZZER_msg(BUZZER_CHILD_ID, V_LIGHT);
void setup()
{
pinMode(W_DIGITAL_INPUT_SENSOR, INPUT); // set pin to input
digitalWrite(W_DIGITAL_INPUT_SENSOR, HIGH); // turn on pullup resistors
// Setup the door switchs 1
pinMode(d1_BUTTON_PIN,INPUT);
// Activate internal pull-up
digitalWrite(d1_BUTTON_PIN,HIGH);
// After setting up the button, setup debouncer
d1_debouncer.attach(d1_BUTTON_PIN);
d1_debouncer.interval(100);
// Setup the door switch 2
pinMode(d2_BUTTON_PIN,INPUT);
// Activate internal pull-up
digitalWrite(d2_BUTTON_PIN,HIGH);
// After setting up the button, setup debouncer
d2_debouncer.attach(d2_BUTTON_PIN);
d2_debouncer.interval(20);
// Setup the deurbel relais
pinMode(O_DEURBEL_PIN,OUTPUT);
digitalWrite(O_DEURBEL_PIN, false);
// Setup the buzzer
pinMode(O_BUZZER_PIN,OUTPUT);
W_lastSend=millis();
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("Meterkast", "2.1");
// Register this device as power sensor
present(W_CHILD_ID, S_WATER);
// Fetch last known pulse count value from gw
request(W_CHILD_ID, V_VAR1);
//present Voordeur
present(d1_CHILD_ID, S_DOOR);
//present Deurbel drukknop
present(d2_CHILD_ID, S_LIGHT);
//present Deurbel disable
present(DIS_DEURBEL_CHILD_ID, S_LIGHT);
send(DIS_DEURBEL_msg.set(0));
//present Deurbel relais
present(BEL_CHILD_ID, S_LIGHT);
//present BUZZER
present(BUZZER_CHILD_ID, S_LIGHT);
}
void loop()
{
unsigned long now = millis();
//unsigned long currentTime = millis();
//Read watermeter input
W_puls = digitalRead(W_DIGITAL_INPUT_SENSOR);
if (W_puls != W_prevpuls)
{
Serial.println("Water puls ontvangen");
W_onPulse();
W_prevpuls = W_puls;
}
// Only send values at a maximum frequency or woken up from sleep
bool W_sendTime = now - W_lastSend > W_SEND_FREQUENCY;
if (W_pcReceived && W_sendTime)
{
if (W_flow != W_oldflow)
{
W_oldflow = W_flow;
Serial.print("l/min:");
Serial.println(W_flow);
// Check that we dont get unresonable large flow value.
// could hapen when long wraps or false interrupt triggered
if (W_flow<((unsigned long)W_MAX_FLOW))
{
send(flowMsg.set(W_flow, 2)); // Send flow value to gw
}
}
// No Pulse count received in 2min
if(now - W_lastPulse > 120000){
W_flow = 0;
}
// Pulse count has changed
if (W_pulseCount != W_oldPulseCount) {
W_oldPulseCount = W_pulseCount;
Serial.print("W_pulsecount:");
Serial.println(W_pulseCount);
send(lastCounterMsg.set(W_pulseCount)); // Send pulsecount value to gw in VAR1
double W_volume = ((double)W_pulseCount/((double)W_PULSE_FACTOR));
if (W_volume != W_oldvolume) {
W_oldvolume = W_volume;
Serial.print("volume:");
Serial.println(W_volume, 3);
send(volumeMsg.set(W_volume, 3)); // Send volume value to gw
}
}
W_lastSend = now;
}
else if (W_sendTime && !W_pcReceived)
{
// No count received. Try requesting it again
request(W_CHILD_ID, V_VAR1);
W_lastSend=now;
}
//Door switch 1
d1_debouncer.update();
// Get the update value
int d1_value = d1_debouncer.read();
//If door status changed
if (d1_value != d1_oldValue)
{
// Send in the new value
send(d1_msg.set(d1_value==HIGH ? 1 : 0));
d1_oldValue = d1_value;
}
//Door switch 2 - Deurbel
d2_debouncer.update();
// Get the update value
int d2_value = d2_debouncer.read();
//If door status changed
if (d2_value != d2_oldValue)
{
if (d2_value == HIGH)
{
digitalWrite(O_DEURBEL_PIN, false);
deurbel_on = false;
}
else
{
if(Bel_Disabled==false)
{
Serial.print("!! Deurbel !!");
digitalWrite(O_DEURBEL_PIN, true);
t_deurbel = millis();
deurbel_on = true;
}
}
// Send in the new value
send(d2_msg.set(d2_value==HIGH ? 0 : 1));
d2_oldValue = d2_value;
}
if(deurbel_on == true && (t_deurbel + T_DEURBEL_ON < now))
{
digitalWrite(O_DEURBEL_PIN, false);
deurbel_on = false;
}
if(W_lastSend > now)
W_lastSend = now;
}
// Check incomming messages
void receive(const MyMessage &message)
{
//If last know water value
if (message.sensor==W_CHILD_ID && message.type==V_VAR1) {
W_pulseCount = W_oldPulseCount = message.getLong();
Serial.print("Received last W_pulse count from gw:");
Serial.println(W_pulseCount);
W_pcReceived = true;
}
//Message of type V_LIGHT ?
if (message.type==V_LIGHT)
{
if (message.sensor==DIS_DEURBEL_CHILD_ID)
{
if(message.getBool()==1)
{
Bel_Disabled = true;
Serial.println("Domoticz --> Deurbel Disabled !!");
}
else
{
Bel_Disabled = false;
Serial.println("Domoticz --> Deurbel Enabled !!");
}
}
}
}
//Puls from watermeter
void W_onPulse()
{
Serial.println("Watermeter");
unsigned long W_newBlink = micros();
unsigned long W_interval = W_newBlink-W_lastBlink;
W_lastBlink = W_newBlink;
if (W_interval!=0)
{
W_lastPulse = millis();
if (W_interval<250000L)
{
// Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
return;
}
W_flow = (60000000.0 /W_interval) / W_ppl;
W_pulseCount++;
}
}