Heater control with rotary encoder

Everything about esp8266 and more.

Moderator: leecollings

Post Reply
Zachtstaart2002
Posts: 3
Joined: Sunday 24 November 2019 16:06
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Heater control with rotary encoder

Post by Zachtstaart2002 »

I was looking to make a stable control for de temperature in my house. The goal was to set a temperature setting by rotary controler and send that setting to domoticz. If the temperature setting is changed by Domoticz user the new temperature setting must be send to NodeMCU.
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&param=switchlight&idx=395&switchcmd=On");
  //  int httpCode = http.GET();
  if (repeat == 10) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=10");
    int httpCode1 = http.GET();
  }
  if (repeat == 11) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=11");
    int httpCode1 = http.GET();
  }
  if (repeat == 12) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=12");
    int httpCode1 = http.GET();
  }
  if (repeat == 13) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=13");
    int httpCode1 = http.GET();
  }
  if (repeat == 14) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=14");
    int httpCode1 = http.GET();
  }
  if (repeat == 15) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=15");
    int httpCode1 = http.GET();
  }
  if (repeat == 16) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=16");
    int httpCode1 = http.GET();
  }
  if (repeat == 17) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=17");
    int httpCode1 = http.GET();
  }
  if (repeat == 18) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=18");
    int httpCode1 = http.GET();
  }
  if (repeat == 19) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=19");
    int httpCode1 = http.GET();
  }
  if (repeat == 20) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=20");
    int httpCode1 = http.GET();
  }
  if (repeat == 21) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=21");
    int httpCode1 = http.GET();
  }
  if (repeat == 22) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=22");
    int httpCode1 = http.GET();
  }
  if (repeat == 23) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=23");
    int httpCode1 = http.GET();
  }
  if (repeat == 24) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=24");
    int httpCode1 = http.GET();
  }
  if (repeat == 25) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=25");
    int httpCode1 = http.GET();
  }
  if (repeat == 26) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=26");
    int httpCode1 = http.GET();
  }
  if (repeat == 27) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=27");
    int httpCode1 = http.GET();
  }
  if (repeat == 28) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=28");
    int httpCode1 = http.GET();
  }
  if (repeat == 29) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=setsetpoint&idx=630&setpoint=29");
    int httpCode1 = http.GET();
  }
  if (repeat == 30) {
    http.begin("http://<YOURE DOMOTICZ IP>:8080/json.htm?type=command&param=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);
}
The LUA script that runs on Domoticz

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
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 1 guest