320 lines
9.0 KiB
C++
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++;
|
|
}
|
|
}
|