I want to 3D print a housing to accomadate a LCD screen 2X16 line one to display temperature set by rotary encoder ans temperature and humidity.
To do that i used two NodeMCU units.
One to run with ESPEASY who will send temperature and humidity to Domotics using a virtual device, and control a relais to turn of or on the heater (central heating system).
The second NodeMCU is running Arduino code i wrote. It controls the rotary encoder to set de temerature inside the house. The temperature set by rotary encoder gets send to a virtual setpoint device in Domotics. If a Domoticz user changes the temperature the seconde NodeMCU receives the change and sends the new temperature to a lcd screen.
To send the new temperature setting from Domoticz i wrote a LUA script that runs on device change.
For me this works fine. It does what i was looking for. Since i could not find much information on how to make a wifi themostat that is compatible with Domoticz.
I hope other hobbyist can use this information. Enjoy
Arduino sketch
Code: Select all
/*
Program for Thermostatic heater control on NodeMCU and Domoticz
The goal is to set a temperature setting by rotary controler and send that setting to domoticz
If the temperature setting is changed by Domoticz user a LUA script send the temperature setting to NodeMCU
LCD screen 2X16 line one to display temperature set by rotary encoder
Line two is used to display temperature and humidity messured by DHT22
Written by Willem Pelkman 24-11-2019
*/
// Used library
#include <RotaryEncoder.h>
#include <ESP8266WiFi.h>
#include "DHT.h"
#include <ESP8266HTTPClient.h>
#include <LiquidCrystal_I2C.h>
// WIFI acces point
#ifndef STASSID
#define STASSID "<YOURE SSID>"
#define STAPSK "<YOURE SSID PASWOORD>"
#endif
// Uncomment one of the lines below for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
// DHT Sensor connected on pin
uint8_t DHTPin = D5;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);
// float to save temperature and humidity
float T;
float H;
// Get SSID value in variable
const char* ssid = STASSID;
const char* password = STAPSK;
// Define rotary encoder pins Note Optional Pins can be -1
const RotaryEncoder::OptPin GND = -1; // Use GND pin
const RotaryEncoder::OptPin VCC = -1; // Use V+ pin
const RotaryEncoder::OptPin SW = -1; // Switch
const RotaryEncoder::Pin DT = D6; // Data
const RotaryEncoder::Pin CLK = D7; // Clock
// define constants
int ledpin = D4; // pin internal led
int repeat = 15; // startup value temperature setting rotary encoder
int temperatuur = 15; // startup value temperature setting webrequest
int prevrepeat = 15; // startup value previus repeat value
int prevtemperatuur = 15; // startup value previus temperatuur value
int timeSinceLastRead = 0; // time the DHT is last read
int startup = 0; // detection first loop to get first value DHT senser before timer starts
// LCD display
int lcdColumns = 16;
int lcdRows = 2;
// char to lose digits after .
char strt[7];
char strh[7];
byte ledState = 0; // ledstate for ledblink
unsigned long ledinterval = 500; // delay for ledblink
unsigned long previousMillis = 0; // previus milles when ledstate changed
// Tell library which pin does what. Note Optional Pins can be -1
RotaryEncoder encoder(GND, VCC, SW, DT, CLK);
// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
// Function to scroll text
// The function acepts the following arguments:
// row: row number where the text will be displayed
// message: message to scroll
// delayTime: delay between each character shifting
// lcdColumns: number of columns of your LCD
void scrollText(int row, String message, int delayTime, int lcdColumns) {
for (int i = 0; i < lcdColumns; i++) {
message = " " + message;
}
message = message + " ";
for (int pos = 0; pos < message.length(); pos++) {
lcd.setCursor(0, row);
lcd.print(message.substring(pos, pos + lcdColumns));
delay(delayTime);
}
}
void setup() {
Serial.begin(115200);
encoder.Begin(1); // Start, with a re-bias of 1
pinMode(DHTPin, INPUT); // DHT pin mode
dht.begin(); // initialize DHT sensor
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
// prepare LED
pinMode(ledpin, OUTPUT);
digitalWrite(ledpin, 0);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print(F("Connecting to "));
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
IPAddress ip(<STATIC IP ADRES FOR NodeMCU);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
WiFi.config(ip, gateway, subnet);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(F("."));
}
Serial.println();
Serial.println(F("WiFi connected"));
// Start the server
server.begin();
Serial.println(F("Server started"));
// Print the IP address
Serial.println(WiFi.localIP());
}
void loop() {
rotatie(); //detect rotary controler change state
vergelijking(); // check if Domoticz or Rotary encoder changed and make value te same
timeSinceLastRead += 1; // Increase counter of last time read DHT sensor
templezer(); // Function to read DHT sensor
led(); // Led blink function
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
Serial.println(F("new client"));
client.setTimeout(5000); // default is 1000
// Read the first line of the request
String req = client.readStringUntil('\r');
Serial.println(F("request: "));
Serial.println(req);
// Match the request coming from Domoticz or HTML page
if (req.indexOf(F("/tempset/10")) != -1) {
temperatuur = 10;
} else if (req.indexOf(F("/tempset/11")) != -1) {
temperatuur = 11;
} else if (req.indexOf(F("/tempset/12")) != -1) {
temperatuur = 12;
} else if (req.indexOf(F("/tempset/13")) != -1) {
temperatuur = 13;
} else if (req.indexOf(F("/tempset/14")) != -1) {
temperatuur = 14;
} else if (req.indexOf(F("/tempset/15")) != -1) {
temperatuur = 15;
} else if (req.indexOf(F("/tempset/16")) != -1) {
temperatuur = 16;
} else if (req.indexOf(F("/tempset/17")) != -1) {
temperatuur = 17;
} else if (req.indexOf(F("/tempset/18")) != -1) {
temperatuur = 18;
} else if (req.indexOf(F("/tempset/19")) != -1) {
temperatuur = 19;
} else if (req.indexOf(F("/tempset/20")) != -1) {
temperatuur = 20;
} else if (req.indexOf(F("/tempset/21")) != -1) {
temperatuur = 21;
} else if (req.indexOf(F("/tempset/22")) != -1) {
temperatuur = 22;
} else if (req.indexOf(F("/tempset/23")) != -1) {
temperatuur = 23;
} else if (req.indexOf(F("/tempset/24")) != -1) {
temperatuur = 24;
} else if (req.indexOf(F("/tempset/25")) != -1) {
temperatuur = 25;
} else if (req.indexOf(F("/tempset/26")) != -1) {
temperatuur = 26;
} else if (req.indexOf(F("/tempset/27")) != -1) {
temperatuur = 27;
} else if (req.indexOf(F("/tempset/28")) != -1) {
temperatuur = 28;
} else if (req.indexOf(F("/tempset/29")) != -1) {
temperatuur = 29;
} else if (req.indexOf(F("/tempset/30")) != -1) {
temperatuur = 30;
} else {
Serial.println(F("invalid request"));
}
// read/ignore the rest of the request
// do not client.flush(): it is for output only, see below
while (client.available()) {
// byte by byte is not very efficient but works
client.read();
}
// Send the response to the HTML page wich can reached on HTTP://<IP NodeMCU>
client.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nTEMPERATUUR pagina"));
client.print(F("<br><br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/10'>here</a> to set temp on 10."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/11'>here</a> to set temp on 11."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/12'>here</a> to set temp on 12."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/13'>here</a> to set temp on 13."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/14'>here</a> to set temp on 14."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/15'>here</a> to set temp on 15."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/16'>here</a> to set temp on 16."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/17'>here</a> to set temp on 17."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/18'>here</a> to set temp on 18."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/19'>here</a> to set temp on 19."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/20'>here</a> to set temp on 20."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/21'>here</a> to set temp on 21."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/22'>here</a> to set temp on 22."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/23'>here</a> to set temp on 23."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/24'>here</a> to set temp on 24."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/25'>here</a> to set temp on 25."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/26'>here</a> to set temp on 26."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/27'>here</a> to set temp on 27."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/28'>here</a> to set temp on 28."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/29'>here</a> to set temp on 29."));
client.print(F("<br>Click <a href='http://"));
client.print(WiFi.localIP());
client.print(F("/tempset/30'>here</a> to set temp on 30.</html><br><br>"));
// print current value of variable to serial for debuging
Serial.print(F("repeat is nu "));
Serial.println((repeat));
Serial.print(F("temperatuur is nu "));
Serial.println((temperatuur));
// The client will actually be *flushed* then disconnected
// when the function returns and 'client' object is destroyed (out-of-scope)
// flush = ensure written data are received by the other side
Serial.println(F("Disconnecting from client"));
}
void rotatie() {
if (encoder.Switch()) { // Hard override! Not used
}
else {
int value = encoder.Get(); // Returns positive for clockwise turn
repeat += value; // We want to INCREASE the value by turning right
if (repeat <= 10) { // minimum temperature setting
repeat = 10;
}
else if (repeat >= 30) { // maximum temperature setting
repeat = 30;
}
if (value != 0) { // Did it change?
Serial.print("Ingestelde Temperatuur "); // Print tekst
Serial.print('=');
Serial.print(" ");
Serial.print(repeat); // Print value of repeat = temperature setting
Serial.println(" Graden Celcius");
}
}
}
void vergelijking() {
// If repeat is changed by turning rotary encoder make temperature the same value
// If temperature is changed by Domoticz webrequest make repeat same value
// advertise new value to Domoticz by PrintInfo
if (prevrepeat != repeat) {
prevrepeat = repeat;
temperatuur = repeat;
prevtemperatuur = repeat;
printInfo();
} else if (prevtemperatuur != temperatuur) {
prevtemperatuur = temperatuur;
repeat = temperatuur;
prevrepeat = temperatuur;
printInfo();
}
}
void templezer() {
if (startup == 0) {
T = dht.readTemperature(); // Gets the values of the temperature
H = dht.readHumidity(); // Gets the values of the humidity
timeSinceLastRead = 0;
dtostrf(T, 2, 0, strt);
dtostrf(H, 2, 0, strh);
Serial.print("Gemeten Temperatuur "); // Print tekst
Serial.print('=');
Serial.print(" ");
Serial.print(T); // Print new result
Serial.println(" Graden Celcius");
Serial.print("Gemeten Vochtigheid "); // Print tekst
Serial.print('=');
Serial.print(" ");
Serial.print(H); // Print new result
Serial.println(" %");
startup = 1;
} else if (timeSinceLastRead > 6000000) {
T = dht.readTemperature(); // Gets the values of the temperature
H = dht.readHumidity(); // Gets the values of the humidity
dtostrf(T, 2, 0, strt);
dtostrf(H, 2, 0, strh);
Serial.print("Gemeten Temperatuur "); // Print tekst
Serial.print('=');
Serial.print(" ");
Serial.print(strt); // Print new result
Serial.println(" Graden Celcius");
Serial.print("Gemeten Vochtigheid "); // Print tekst
Serial.print('=');
Serial.print(" ");
Serial.print(strh); // Print new result
Serial.println(" %");
timeSinceLastRead = 0;
printInfo();
}
}
void printInfo()
{
// Send changes to Domoticz by json command set idx value as needed
HTTPClient http; //Object of class HTTPClient
// http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=switchlight&idx=395&switchcmd=On");
// int httpCode = http.GET();
if (repeat == 10) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=10");
int httpCode1 = http.GET();
}
if (repeat == 11) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=11");
int httpCode1 = http.GET();
}
if (repeat == 12) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=12");
int httpCode1 = http.GET();
}
if (repeat == 13) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=13");
int httpCode1 = http.GET();
}
if (repeat == 14) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=14");
int httpCode1 = http.GET();
}
if (repeat == 15) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=15");
int httpCode1 = http.GET();
}
if (repeat == 16) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=16");
int httpCode1 = http.GET();
}
if (repeat == 17) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=17");
int httpCode1 = http.GET();
}
if (repeat == 18) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=18");
int httpCode1 = http.GET();
}
if (repeat == 19) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=19");
int httpCode1 = http.GET();
}
if (repeat == 20) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=20");
int httpCode1 = http.GET();
}
if (repeat == 21) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=21");
int httpCode1 = http.GET();
}
if (repeat == 22) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=22");
int httpCode1 = http.GET();
}
if (repeat == 23) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=23");
int httpCode1 = http.GET();
}
if (repeat == 24) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=24");
int httpCode1 = http.GET();
}
if (repeat == 25) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=25");
int httpCode1 = http.GET();
}
if (repeat == 26) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=26");
int httpCode1 = http.GET();
}
if (repeat == 27) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=27");
int httpCode1 = http.GET();
}
if (repeat == 28) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=28");
int httpCode1 = http.GET();
}
if (repeat == 29) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=29");
int httpCode1 = http.GET();
}
if (repeat == 30) {
http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command¶m=setsetpoint&idx=630&setpoint=30");
int httpCode1 = http.GET();
}
}
void led() {
// Led blink function whitout delay
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= ledinterval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == 0)
ledState = 1;
else
ledState = 0;
// set the LED with the ledState of the variable:
digitalWrite(ledpin, ledState);
}
}
void scroltext() {
// Tekst to print on LCD display
String messageStatic = "Temp ";
int stringOne = repeat;
String messageStatic2 = " setting";
String stringTwo = messageStatic + stringOne + messageStatic2;
// set cursor to first column, first row
lcd.setCursor(0, 0);
lcd.print(stringTwo);
String str0 = "Gemeten temperatuur = ";
float str1 = T;
String str2 = " Graden Celcuis";
String str3 = " Gemeten vochtigheid = ";
float str4 = H;
String str5 = " %";
String messageToScroll = str0 + str1 + str2 + str3 + str4 + str5;
scrollText(1, messageToScroll, 250, lcdColumns);
}
Code: Select all
commandArray = {}
for deviceName,deviceValue in pairs(otherdevices) do
if (deviceName=='NodeMCU') then
print('NodeMCU found')
local tempset = tostring(deviceValue)
if (uservariables["prevtempset"] ~= tempset) then
print("vorigeTemp = "..(uservariables["prevtempset"]))
print("tempset = "..(tempset))
if (uservariables["prevtempset"] ~= tempset) then commandArray['Variable:prevtempset'] = tostring(tempset) end
print('Temp verzenden')
if tempset == "10.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/10"')
elseif tempset == "11.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/11"')
elseif tempset == "12.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/12"')
elseif tempset == "13.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/13"')
elseif tempset == "14.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/14"')
elseif tempset == "15.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/15"')
elseif tempset == "16.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/16"')
elseif tempset == "17.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/17"')
elseif tempset == "18.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/18"')
elseif tempset == "19.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/19"')
elseif tempset == "20.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/20"')
elseif tempset == "21.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/21"')
elseif tempset == "22.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/22"')
elseif tempset == "23.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/23"')
elseif tempset == "24.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/24"')
elseif tempset == "25.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/25"')
elseif tempset == "26.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/26"')
elseif tempset == "27.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/27"')
elseif tempset == "28.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/28"')
elseif tempset == "29.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/29"')
elseif tempset == "30.00" then
os.execute ('curl -s "http://<YOURE NodeMCU IP>/tempset/30"')
end
end
end
end
return commandArray