hello guys. i changed @dpressle scketch for work with our South European shutters. that means now work with a standard shutter mechanical wall switch, without stop ,and 2 relays ,one for up ,one for down and all shutter motors have mechanic limits/stoppers embedded,So i don't pay much attention to calibrate or have exact stop time. I removed the calibration code and i add manually the exact time that windows shutter take to open +1sec (for be sure it reach mechanical limit).
Stop is now on release(fall) any key from the mechanical switch(up or down), and in power fail case ,it stays were it was left and start counting up or down from there.
Unfortunately if you use Domoticz ,percentage appear be not supported... And without any v_status on code,appear that domoticz don't know if state is open or close,but respond to close and open and stop like blind switch/sensor.
// Enable debug prints to serial monitor
#define MY_DEBUG
// Enable and select radio type attached
#define MY_RADIO_RFM69
//#define MY_RF24_PA_LEVEL RF24_PA_LOW
//#define MY_REPEATER_FEATURE
#include <Bounce2.h>
#include <MySensors.h>
#include <SPI.h>
// uncomment if we want to manually assign an ID
//#define MY_NODE_ID 1 /
#define BUTTON_UP_PIN 5 // Arduino Digital I/O pin number for up button
#define BUTTON_DOWN_PIN 6 // Arduino Digital I/O pin number for down button
//#define BUTTON_STOP_PIN 7 // Arduino Digital I/O pin number for stop button
#define RELAY_UP_PIN 3 // Arduino Digital I/O pin number for direction relay
#define RELAY_DOWN_PIN 4 // Arduino Digital I/O pin number for power relay
#define RELAY_ON 0
#define RELAY_OFF 1
//#define RELAY_DOWN 1
//#define RELAY_UP 0
#define DIRECTION_DOWN 1
#define DIRECTION_UP 0
#define SKETCH_NAME "Cover"
#define SKETCH_VER "2.0"
#define CHILD_ID_COVER 0 // sensor Id of the sensor child
#define STATE_UP 100 // 100 is open - up
#define STATE_DOWN 0 // 0 is closed - down
//#define CHILD_ID_CALIBRATE 1 // sensor Id of the sensor child to calibrate
#define CHILD_ID_SET 1 // sensor Id of the sensor child to init the roll time
#define PRESENT_MESSAGE "shuttle for Livingroom"
const int LEVELS = 100; //the number of levels
float rollTime = 28.0; //the overall rolling time of the shutter
const bool IS_ACK = false; //is to acknowlage
static bool initial_state_sent = false;//for hass we need at list one state send at begining
// debouncing parameters
int value = 0;
int oldValueUp = 0;
int oldValueDown = 0;
//int value1=0;int value2=0;
int oldValueStop=0;
int oldValueStop1=0;
//static unsigned long last_interrupt_time_up = 0;
//static unsigned long last_interrupt_time_down = 0;
//static unsigned long debounce_time = 200;
Bounce debouncerUp = Bounce();
Bounce debouncerDown = Bounce();
//Bounce debouncerStop = Bounce();
// shutter position parameters
float timeOneLevel = rollTime / LEVELS;
int requestedShutterLevel = 0;
int currentShutterLevel = 0;
unsigned long lastLevelTime = 0;
bool isMoving = false;
int directionUpDown;
enum CoverState {
STOP,
UP, // Window covering. Up.
DOWN, // Window covering. Down.
};
static int coverState = STOP;
MyMessage msgUP(CHILD_ID_COVER, V_UP);
MyMessage msgDown(CHILD_ID_COVER, V_DOWN);
MyMessage msgStop(CHILD_ID_COVER, V_STOP);
MyMessage msgPercentage(CHILD_ID_COVER, V_PERCENTAGE);
void sendState() {
// Send current state and status to gateway.
send(msgUP.set(coverState == UP));
send(msgDown.set(coverState == DOWN));
send(msgStop.set(coverState == STOP));
send(msgPercentage.set(currentShutterLevel));
}
void shuttersUp(void) {
#ifdef MY_DEBUG
Serial.println("Shutters going up");
#endif
if (digitalRead(RELAY_DOWN_PIN) == RELAY_ON) {
digitalWrite(RELAY_DOWN_PIN, RELAY_OFF);
delay(100);
}
digitalWrite(RELAY_UP_PIN, RELAY_ON);
directionUpDown = DIRECTION_UP;
isMoving = true;
coverState = UP;
sendState();
}
void shuttersDown(void) {
#ifdef MY_DEBUG
Serial.println("Shutters going down");
#endif
if (digitalRead(RELAY_UP_PIN) == RELAY_ON) {
digitalWrite(RELAY_UP_PIN, RELAY_OFF);
delay(100);
}
digitalWrite(RELAY_DOWN_PIN, RELAY_ON);
directionUpDown = DIRECTION_DOWN;
isMoving = true;
coverState = DOWN;
sendState();
}
void shuttersHalt(void) {
#ifdef MY_DEBUG
Serial.println("Shutters halted X");
#endif
digitalWrite(RELAY_UP_PIN, RELAY_OFF);
digitalWrite(RELAY_DOWN_PIN, RELAY_OFF);
delay(100);
//}
isMoving = false;
requestedShutterLevel = currentShutterLevel;
#ifdef MY_DEBUG
Serial.println("saving state to: ");
Serial.println(String(currentShutterLevel));
#endif
saveState(CHILD_ID_COVER, currentShutterLevel);
coverState = STOP;
//sendState();
}
void changeShuttersLevel(int level) {
int dir = (level > currentShutterLevel) ? DIRECTION_UP : DIRECTION_DOWN;
if (isMoving && dir != directionUpDown) {
shuttersHalt();
}
requestedShutterLevel = level;
}
void receive(const MyMessage &message) {
#ifdef MY_DEBUG
Serial.println("recieved incomming message");
Serial.println("Recieved message for sensor: ");
Serial.println(String(message.sensor));
Serial.println("Recieved message with type: ");
Serial.println(String(message.type));
#endif
if (message.sensor == CHILD_ID_COVER) {
switch (message.type) {
case V_UP:
//Serial.println(", New status: V_UP");
changeShuttersLevel(STATE_UP);
break;
case V_DOWN:
//Serial.println(", New status: V_DOWN");
changeShuttersLevel(STATE_DOWN);
break;
case V_STOP:
//Serial.println(", New status: V_STOP");
shuttersHalt();
break;
case V_PERCENTAGE:
int per = message.getInt();
if (per > STATE_UP) {
per = STATE_UP;
}
changeShuttersLevel(per);
break;
}
}
#ifdef MY_DEBUG
Serial.println("exiting incoming message");
#endif
return;
}
void before() {
// Setup the button
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
// Activate internal pull-up
digitalWrite(BUTTON_UP_PIN, HIGH);
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP);
// Activate internal pull-up
digitalWrite(BUTTON_DOWN_PIN, HIGH);
// After setting up the button, setup debouncer
debouncerUp.attach(BUTTON_UP_PIN);
debouncerUp.interval(5);
// After setting up the button, setup debouncer
debouncerDown.attach(BUTTON_DOWN_PIN);
debouncerDown.interval(5);
// Make sure relays are off when starting up
digitalWrite(RELAY_UP_PIN, RELAY_OFF);
// Then set relay pins in output mode
pinMode(RELAY_UP_PIN, OUTPUT);
// Make sure relays are off when starting up
digitalWrite(RELAY_DOWN_PIN, RELAY_OFF);
// Then set relay pins in output mode
pinMode(RELAY_DOWN_PIN, OUTPUT);
}
void presentation() {
// Send the sketch version information to the gateway and Controller
sendSketchInfo(SKETCH_NAME, SKETCH_VER);
// Register all sensors to gw (they will be created as child devices)
present(CHILD_ID_COVER, S_COVER, PRESENT_MESSAGE, IS_ACK);
//present(CHILD_ID_SET, S_CUSTOM);
}
void setup(void) {
int state = loadState(CHILD_ID_COVER);
#ifdef MY_DEBUG
Serial.println("getting state from eeprom: ");
Serial.println(String(state));
#endif
currentShutterLevel=state;
changeShuttersLevel(state);
}
void loop(void) {
if (!initial_state_sent) {
#ifdef MY_DEBUG
Serial.println("Sending initial value");
#endif
sendState();
initial_state_sent = true;
}
debouncerUp.update();
value = debouncerUp.read();
if (value == 0 && value != oldValueUp) {
changeShuttersLevel(STATE_UP);
}
oldValueUp = value;
debouncerDown.update();
value = debouncerDown.read();
if (value == 0 && value != oldValueDown) {
changeShuttersLevel(STATE_DOWN);
}
oldValueDown = value;
value = debouncerUp.rose();
if ((value == 0) && (value != oldValueStop) &&(isMoving==true)){
shuttersHalt();
}
oldValueStop = value;
value = debouncerDown.rose();
if ((value) == 0 && (value != oldValueStop1)&&(isMoving==true)){
shuttersHalt();
}
oldValueStop1 = value;
if (isMoving) {
unsigned long _now = millis();
if (_now - lastLevelTime >= timeOneLevel * 1000) {
if (directionUpDown == DIRECTION_UP) {
currentShutterLevel += 1;
} else {
currentShutterLevel -= 1;
}
#ifdef MY_DEBUG
//Serial.println(String(requestedShutterLevel));
Serial.println(String(currentShutterLevel));
#endif
lastLevelTime = millis();
//send(msgPercentage.set(currentShutterLevel));
}
if (currentShutterLevel == requestedShutterLevel){
shuttersHalt();
}
}
else if (requestedShutterLevel != currentShutterLevel) {
if (requestedShutterLevel > currentShutterLevel) {
shuttersUp();
}
else {
shuttersDown();
}
lastLevelTime = millis();
}
}