No time to optimize the code but here it is...
On the Arduino Nano the following code is running:
Code: Select all
/**
File: LCDemo A Mysensors demo project for interaction with Domoticz
Hardware: Arduino NANO
Functions: Show 3 lines on LCD (Nokia 5110) with text from Domoticz
Control backlight of LCD by Domoticz switch
PIR sensor on interrupt pin as motion sensor on Domoticz
LDR sensor on analog port to show light level on Domoticz
obsolete: change contrast of LCD with Domoticz slider (does work but not usefull)
Uses Domoticz switch to trigger LCD updates (CHILD_ID_STAT)
By: Gerard - 2017
*/
#define SKETCH_NAME "LCDemo"
#define SKETCH_VERSION "1.8.2"
#define MESSAGEWAIT 500
// Nokia 5110 LCD - 84 x 48 pixels
#include <LCD5110_Graph.h>
//LCD5110 myGLCD(7, 6, 5, 3, 4);
LCD5110 myGLCD(7, 6, 5, 18, 4); // pin 3 has moved to 18(A5) because we need interrupt pin 3
extern uint8_t SmallFont[]; // 6x8 pixels max 14 chars x 5 lines
extern unsigned char TinyFont[]; // 4x6 pixels max 21 chars X lines
String lcdLine[5];
#define PIR_PIN 3 // PIR sensor
#define LIGHT_SENSOR_ANALOG_PIN A0 // LDR sensor
#define RELAY_PIN 8 // Actually not a relay anymore but the LCD backlight now
#define RELAY_ON 1 // GPIO value to write to turn on attached relay
#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
#define MY_DEBUG
#define MY_RADIO_NRF24
#define MY_NODE_ID 10
//#define MY_REPEATER_FEATURE
#include <MySensors.h>
#define CHILD_ID_RELAY 0
#define CHILD_ID_LCD1 1 // LCD line 1
#define CHILD_ID_LCD2 2 // LCD line 2
#define CHILD_ID_LCD3 3 // LCD line 3
#define CHILD_ID_DIMMER 4
#define CHILD_ID_LDR 5
#define CHILD_ID_PIR 6
#define CHILD_ID_STAT 7 // test with v_status s_binary to trigger request lcd line info
MyMessage textMsg1(CHILD_ID_LCD1, V_TEXT);
MyMessage textMsg2(CHILD_ID_LCD2, V_TEXT);
MyMessage textMsg3(CHILD_ID_LCD3, V_TEXT);
MyMessage dimmerMsg(CHILD_ID_DIMMER, V_DIMMER);
MyMessage lightMsg(CHILD_ID_DIMMER, V_LIGHT);
MyMessage LdrMsg(CHILD_ID_LDR, V_LIGHT_LEVEL);
MyMessage PirMsg(CHILD_ID_PIR, V_TRIPPED);
MyMessage StatMsg(CHILD_ID_STAT, V_STATUS);
static const uint64_t UPDATE_INTERVAL = 60000;
unsigned long currentMillis = 0;
volatile unsigned long previousMillis = 0;
volatile bool pirEvent = true;
static int16_t currentLevel = 0; // Current dim level...
bool lcdUpdate = false;
bool lcdUpdate1 = false;
bool lcdUpdate2 = false;
bool lcdUpdate3 = false;
bool lastPir = false;
int LightLevel = 0;
int PreviousLightLevel = 0;
bool domoTrigger = false;
bool runOnce = true;
void before()
{
pinMode(RELAY_PIN, OUTPUT);
//digitalWrite(RELAY_PIN, loadState(sensor)?RELAY_ON:RELAY_OFF);
digitalWrite(RELAY_PIN, RELAY_ON); // for now force backlight on
}
void setup()
{
lcdLine[0][0] = 0;
lcdLine[0] = SKETCH_NAME;
lcdLine[0].concat(" ");
lcdLine[0].concat(SKETCH_VERSION);
lcdLine[1] = "--------------";
lcdLine[2] = "--------------";
lcdLine[3] = "--------------";
lcdLine[4] = "..............";
myGLCD.InitLCD();
myGLCD.setFont(SmallFont);
myGLCD.clrScr();
myGLCD.print(lcdLine[0], CENTER, 0);
myGLCD.update();
myGLCD.setContrast(70);
request(CHILD_ID_RELAY, V_STATUS);
wait(MESSAGEWAIT);
request(CHILD_ID_DIMMER, V_DIMMER );
wait(MESSAGEWAIT);
request(CHILD_ID_LCD1, V_TEXT);
wait(MESSAGEWAIT);
request(CHILD_ID_LCD2, V_TEXT);
wait(MESSAGEWAIT);
request(CHILD_ID_LCD3, V_TEXT);
pinMode(PIR_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(PIR_PIN), pirChange, CHANGE);
pinMode(LIGHT_SENSOR_ANALOG_PIN, INPUT_PULLUP);
LightLevel = (1023 - analogRead(LIGHT_SENSOR_ANALOG_PIN)) / 10.23;
PreviousLightLevel = 0;
}
void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo(SKETCH_NAME, SKETCH_VERSION, true);
Serial.print(F("NodeID: "));
Serial.println(getNodeId());
present(CHILD_ID_RELAY, S_BINARY, "RelayP8");
wait(MESSAGEWAIT);
present(CHILD_ID_LCD1, S_INFO, "LCD_line1", true); // new S_type 20150905 (not known by domoticz)
wait(MESSAGEWAIT);
present(CHILD_ID_LCD2, S_INFO, "LCD_line2", true);
wait(MESSAGEWAIT);
present(CHILD_ID_LCD3, S_INFO, "LCD_line3", true);
wait(MESSAGEWAIT);
present(CHILD_ID_DIMMER, S_DIMMER );
wait(MESSAGEWAIT);
present(CHILD_ID_LDR, S_LIGHT_LEVEL, "LDR");
wait(MESSAGEWAIT);
present(CHILD_ID_PIR, S_MOTION, "PIR");
wait(MESSAGEWAIT);
present(CHILD_ID_STAT, S_BINARY, "LCD_Trigger");
}
void loop()
{
if (runOnce) {
send(textMsg1.setSensor(CHILD_ID_LCD1).set("lcd1 waiting")); // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
wait(MESSAGEWAIT);
send(textMsg2.setSensor(CHILD_ID_LCD2).set("lcd2 waiting"));
wait(MESSAGEWAIT);
send(textMsg3.setSensor(CHILD_ID_LCD3).set("lcd3 waiting"));
runOnce = false;
}
if (lcdUpdate1 && lcdUpdate2 && lcdUpdate3) { // check if all 3 lcd lines are received before update entire display
lcdUpdate = true;
}
unsigned long currentMillis = millis();
if ((currentMillis - previousMillis >= UPDATE_INTERVAL) || pirEvent || domoTrigger || lcdUpdate) {
previousMillis = currentMillis;
// Handle PIR sensor
if (pirEvent) {
bool pirTripped = digitalRead(PIR_PIN) == HIGH; // reading twice has not much use. To be optimised...
Serial.print("PIR:"); Serial.println(pirTripped);
myGLCD.invert(pirTripped);
send(PirMsg.setSensor(CHILD_ID_PIR).set(pirTripped ? "1" : "0"));
pirEvent = false;
}
// Handle LCD triggers
if (domoTrigger) { // evidently received a trigger from Domoticz so send requests until all lines are received
if (lcdUpdate1 == false) {
request(CHILD_ID_LCD1, V_TEXT);
wait(MESSAGEWAIT);
}
if (lcdUpdate2 == false) {
request(CHILD_ID_LCD2, V_TEXT);
wait(MESSAGEWAIT);
}
if (lcdUpdate3 == false) {
request(CHILD_ID_LCD3, V_TEXT);
wait(MESSAGEWAIT);
}
if (lcdUpdate1 && lcdUpdate2 && lcdUpdate3) {
domoTrigger = false;
send(StatMsg.setSensor(CHILD_ID_STAT).set("0")); // reset trigger switch on Domoticz
}
}
// Handle LDR sensor data
LightLevel = (1023 - analogRead(LIGHT_SENSOR_ANALOG_PIN)) / 10.23;
Serial.print("Lux:"); Serial.println(LightLevel);
if (LightLevel != PreviousLightLevel) {
send(LdrMsg.setSensor(CHILD_ID_LDR).set(LightLevel));
lcdLine[4] = "Lux: ";
lcdLine[4].concat(LightLevel);
lcdUpdate = true;
PreviousLightLevel = LightLevel;
}
// Update the LCD if required
if (lcdUpdate ) {
myGLCD.clrScr();
myGLCD.print(lcdLine[0], LEFT, 0);
myGLCD.print(lcdLine[1], LEFT, 10);
myGLCD.print(lcdLine[2], LEFT, 20);
myGLCD.print(lcdLine[3], LEFT, 30);
myGLCD.print(lcdLine[4], LEFT, 40);
myGLCD.update();
lcdUpdate = false;
lcdUpdate1 = false; lcdUpdate2 = false; lcdUpdate3 = false;
}
}
}
//
// PIR interrupt routine
//
void pirChange()
{
pirEvent = true;
previousMillis = 0;
}
//
// Callback routine for receiving messages
//
void receive(const MyMessage & message)
{
#ifdef MY_DEBUG
Serial.print("RX:"); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
#endif
// check incoming LCD line text
switch (message.sensor) {
case 1:
lcdLine[1] = message.getString();
lcdUpdate1 = true;
break;
case 2:
lcdLine[2] = message.getString();
lcdUpdate2 = true;
break;
case 3:
lcdLine[3] = message.getString();
lcdUpdate3 = true;
break;
default:
//lcdLine[4] = message.getString();
break;
}
// Check for Trigger
if ((message.type == V_STATUS) and (message.sensor == CHILD_ID_STAT)) {
// force lcd line get from domoticz update
if (message.getBool() == true) {
domoTrigger = true;
Serial.println("lcd update from Domoticz");
}
}
// Backlight on or off
if ((message.type == V_STATUS) and (message.sensor == CHILD_ID_RELAY)) {
// Change relay state
digitalWrite(RELAY_PIN, message.getBool() ? RELAY_ON : RELAY_OFF);
// Store state in eeprom
//saveState(message.sensor, message.getBool());
// Write some debug info
Serial.print("Incoming change for sensor:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(message.getBool());
}
// Obsolete code and to be removed. Was used to control LCD contrast.
if (message.type == V_LIGHT || message.type == V_DIMMER) {
// Retrieve the power or dim level from the incoming request message
int requestedLevel = atoi( message.data ) ;
// Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
requestedLevel *= ( message.type == V_LIGHT ? 80 : 1 );
// Clip incoming level to valid range of 0 to 100 (50-80)
requestedLevel = requestedLevel > 80 ? 80 : requestedLevel;
requestedLevel = requestedLevel < 0 ? 50 : requestedLevel;
Serial.print( "Changing level to " );
Serial.print( requestedLevel );
Serial.print( ", from " );
Serial.println( currentLevel );
//fadeToLevel( requestedLevel );
//myGLCD.setContrast(requestedLevel);
// Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
send(lightMsg.set(currentLevel > 0));
// hek comment: Is this really nessesary?
send( dimmerMsg.set(currentLevel) );
}
}
On Domoticz this code creates the following devices:
Within Domoticz the following event is running (no dzVents yet, someone has to rewrite this part)
Code: Select all
commandArray = {}
local m = os.date('%M')
if (m % 5 == 0) then
print("The 5 minute script interval reached")
s = otherdevices_lastupdate['LCD_Trigger']
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
t1 = os.time()
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = (os.difftime (t1, t2))
sTemp, sHumidity = otherdevices_svalues['msTempHum']:match("([^;]+);([^;]+)")
sSchuurTemp, sSchuurHumidity = otherdevices_svalues['Buienradar - Barometer']:match("([^;]+);([^;]+)")
regen = math.floor(tonumber(otherdevices_svalues['Rain2Come - Rain2Come']))
ttlcd1 = otherdevices_idx['LCD_line1']
ttlcd2 = otherdevices_idx['LCD_line2']
ttlcd3 = otherdevices_idx['LCD_line3']
ttTrig = otherdevices_idx['LCD_Trigger']
commandArray[1] = { ['UpdateDevice'] = ttlcd1..'|0|'..'Regen: '..regen }
commandArray[2] = { ['UpdateDevice'] = ttlcd2..'|0|'..'T:'..sSchuurTemp..' H:'..sSchuurHumidity..'%'}
commandArray[3] = { ['UpdateDevice'] = ttlcd3..'|0|'..'T:'..sTemp..' H:'..sHumidity..'%' }
if (difference > 120) then
commandArray[4] = { ['LCD_Trigger'] = "On" }
end
end
return commandArray
Just for illustration, the devices on the domo panel
Hopefully this helps a bit.
--Gerard