Подключение «Аквасторожа» к «умному дому» на Z-Wave
//#define _DEBUG
#define OPEN_PIN 11
#define CLOSE_PIN 12
#define LEAK_PIN 19
#define INT1 18
uint8_t valve_action = 0;
#ifdef _DEBUG
uint8_t const METER1_PIN = 8;
#else
uint8_t const METER1_PIN = 7;
#endif
#define METER2_PIN 8
#include "EEPROM.h"
#define MAGIC_VALUE 42
#define ADDR_ACTION 1
#define CH_METER_1 4
#define CH_METER_2 8
#define CNT_ON_OFF_CICL 12
// Global variables
byte pin7SwitchBinaryState = 0;
DWORD eeprom_buf = 0;
#define LEAK_CHANNEL 3
DWORD meter_cnt1;
DWORD meter_cnt2;
#define ADR_MET1 4
#define ADR_MET2 5
uint8_t alarm_clr = LOW;
// Z-Wave channels
ZUNO_SETUP_CHANNELS(
ZUNO_SWITCH_BINARY(pin7SwitchBinaryGetter, pin7SwitchBinarySetter),
ZUNO_SWITCH_BINARY(alarmGetter, alarmSetter),
ZUNO_SENSOR_BINARY(ZUNO_SENSOR_BINARY_TYPE_WATER, getterSensorBinary),
ZUNO_METER(ZUNO_METER_TYPE_WATER, METER_RESET_ENABLE , ZUNO_METER_WATER_SCALE_PULSECOUNT, 4, 0, getterMETER1, resetterMETER1),
ZUNO_METER(ZUNO_METER_TYPE_WATER, METER_RESET_ENABLE , ZUNO_METER_WATER_SCALE_PULSECOUNT, 4, 0, getterMETER2, resetterMETER2)
);
ZUNO_SETUP_BATTERY_LEVELS(2700, 3300);
ZUNO_SETUP_SLEEPING_MODE(ZUNO_SLEEPING_MODE_FREQUENTLY_AWAKE);
void close_water()
{
#ifdef _DEBUG
Serial1.println("close");
#endif
digitalWrite(CLOSE_PIN, HIGH);
delay(1000);
digitalWrite(CLOSE_PIN, LOW);
//delay(1000);
}
void open_water()
{
#ifdef _DEBUG
Serial1.println("open");
#endif
digitalWrite(OPEN_PIN, HIGH);
delay(1000);
digitalWrite(OPEN_PIN, LOW);
//delay(1000);
}
#define LEAK_DETECTED LOW
#define LEAK_END HIGH
#define ADDR_LEAK_ST_LAST 2
#define ADR_B1_F 3
#define ADR_B2_F 4
#define NZ_ADR_LEAK 5
uint8_t last_leak_st;
#define EEPROM_MAGIC 0x11223342
#define EEPROM_ADR_MAGIC 0
void setup()
{
#ifdef _DEBUG
Serial1.begin(9600);
Serial1.println("serial init");
#else
pinMode(METER1_PIN, INPUT);
pinMode(METER2_PIN, INPUT);
#endif
pinMode(CLOSE_PIN, OUTPUT);
pinMode(OPEN_PIN, OUTPUT);
pinMode(LEAK_PIN, INPUT_PULLUP);
pinMode(INT1, INPUT_PULLUP);
digitalWrite(CLOSE_PIN, LOW);
digitalWrite(OPEN_PIN, LOW);
byte n;
NZRAM.get(0x0, &n, 1);
if (n == MAGIC_VALUE)
{
// correct magic value after wake up from sleep mode
// trust NZRAM data
}
else
{
// incorrect magic, first boot after battery insert ot rebooted due to low battery
// initialize NZRAM magic
n = MAGIC_VALUE;
NZRAM.put(0x0, &n, 1);
NZRAM.write(ADDR_ACTION, LOW);
NZRAM.write(ADDR_LEAK_ST_LAST, LEAK_END);
NZRAM.write(ADR_B1_F, HIGH);
NZRAM.write(ADR_B2_F, HIGH);
}
EEPROM.get(EEPROM_ADR_MAGIC, &eeprom_buf, sizeof(DWORD));
if(eeprom_buf != EEPROM_MAGIC)
{
eeprom_buf = EEPROM_MAGIC;
EEPROM.put(EEPROM_ADR_MAGIC, &eeprom_buf, sizeof(DWORD));
resetterMETER1();
resetterMETER2();
eeprom_buf = 0;
EEPROM.put(CNT_ON_OFF_CICL, &eeprom_buf, sizeof(DWORD));
}
}
uint8_t last_btn_st;
void check_btn(uint8_t meter_pin, uint8_t NZ_adr_st)
{
last_btn_st = NZRAM.read(NZ_adr_st);
if(digitalRead(meter_pin) == LOW)
{
if(last_btn_st != LOW)
{
for(uint8_t i=0; i<3; ++i)
{
if(digitalRead(meter_pin) == LOW)
delay(5);
else
return;
}
last_btn_st = LOW;
NZRAM.write(NZ_adr_st, last_btn_st);
}
}
else
{
if(last_btn_st == LOW)
{
for(uint8_t i=0; i<3; ++i)
{
if(digitalRead(meter_pin) == HIGH)
delay(5);
else
return;
}
last_btn_st = HIGH;
NZRAM.write(NZ_adr_st, last_btn_st);
if(NZ_adr_st == ADR_B1_F)
inc_met(ADR_MET1);
else
inc_met(ADR_MET2);
}
}
}
//=-----------------------------------------------------------
void loop()
{
if(digitalRead(LEAK_PIN) == LEAK_DETECTED)
{
if(NZRAM.read(ADDR_LEAK_ST_LAST) != LEAK_END)
{
zunoSendReport(LEAK_CHANNEL);
NZRAM.write(ADDR_LEAK_ST_LAST, LEAK_END);
}
}
check_btn(METER1_PIN, ADR_B1_F);
check_btn(METER2_PIN, ADR_B2_F);
if(zunoGetWakeReason() == ZUNO_WAKEUP_REASON_RADIO)
{
uint32_t start_time=0;
#define ACTION_T_OUT 2000
start_time = millis();
//while(NZRAM.read(ADDR_ACTION)== 0)
while(valve_action== 0)
if((millis() - start_time) >= ACTION_T_OUT)
{
#ifdef _DEBUG
Serial1.println("T_OUT");
#endif
break;
}
else
delay(50);
#ifdef _DEBUG
Serial1.println(millis() - start_time);
#endif
if(NZRAM.read(ADDR_ACTION))
{
valve_action = 0;
NZRAM.write(ADDR_ACTION, LOW);
if(pin7SwitchBinaryState == LOW)
close_water();
else
open_water();
}
if(alarm_clr) // Если пришла команда сброса тревоги
{
alarm_clr == LOW;
zunoSendReport(LEAK_CHANNEL);
}
}
if(digitalRead(INT1)==0)
{
zunoSetWUOptions(ZUNO_WUPFLAGS_INT1_HIGH);
}
else
{
zunoSetWUOptions(ZUNO_WUPFLAGS_INT1_LOW);
}
zunoSendDeviceToSleep();
}
//-----------------------------------------------------------
// Getters and setters
void inc_met(uint8_t num_chennel)
{
uint8_t eeprom_adr_met;
if(num_chennel == ADR_MET1)
eeprom_adr_met = CH_METER_1;
else
eeprom_adr_met = CH_METER_2;
EEPROM.get(eeprom_adr_met, &eeprom_buf, sizeof(DWORD));
eeprom_buf++;
EEPROM.put(eeprom_adr_met, &eeprom_buf, sizeof(DWORD));
zunoSendReport(num_chennel);
}
DWORD getterMETER1()
{
EEPROM.get(CH_METER_1, &eeprom_buf, sizeof(DWORD));
return eeprom_buf;
}
DWORD getterMETER2()
{
EEPROM.get(CH_METER_2, &eeprom_buf, sizeof(DWORD));
return eeprom_buf;
}
void resetterMETER1()
{
eeprom_buf = 0;
EEPROM.put(CH_METER_1, &eeprom_buf, sizeof(DWORD));
}
void resetterMETER2()
{
eeprom_buf = 0;
EEPROM.put(CH_METER_2, &eeprom_buf, sizeof(DWORD));
}
void pin7SwitchBinarySetter(byte value)
{
valve_action = 1;
NZRAM.write(ADDR_ACTION, HIGH);
pin7SwitchBinaryState = value;
if(value == 255) // if open valve, then off leak alarm
{
NZRAM.write(ADDR_LEAK_ST_LAST, LOW);
zunoSendReport(LEAK_CHANNEL);
}
}
byte pin7SwitchBinaryGetter() {
return pin7SwitchBinaryState ? 0xFF : 0;
}
byte getterSensorBinary() {
return digitalRead(LEAK_PIN) ? 0 : 0xFF;
}
byte alarmGetter()
{
uint8_t ret;
ret = NZRAM.read(ADDR_LEAK_ST_LAST);
return ret ? 0xFF : 0;
}
void alarmSetter(byte value)
{
alarm_clr = HIGH;
NZRAM.write(ADDR_LEAK_ST_LAST, value);
}