OpenHAB, MQTT, Arduino and ESP8266: Part 5.2: Combined Switch and Sensor module based on Arduino

The following series of posts will document my journey to full Home Automation using the MQTT protocol, all custom hardware (Arduino and ESP8266 based), and all tied together using OpenHAB

  • Part 1:  Setting up the server / environment
  • Part 2:  Publish, Subscribe, Command, State, and WTFs
  • Part 3:  Hardware:  Arduino with Ethernet Shield
  • Part 4:  Hardware:  ESP8266 with NodeMCU firmware
  • Part 5:  Hardware:  Sensors
    • Part 5.1:  Graphing Sensor Data
    • Part 5.2:  Combined Switch and Sensor
  • Part 6:  OpenHAB Automation Rules

This is a very quick post just to jot down a very simple mashup of Part 3 and Part 5.  The sketch below listens for MQTT messages to switch, at every second, but only sends temperature updates every 5 seconds…  Good tradeoff = always available to switch immediately, yet still low bandwidth since it doesnt send a temp update on each cycle of the loop:

Another twist here is that I added a physical button on D7 that also turns the device on/off and then publishes the state back to MQTT -> openhab so the virtual switch status matches what the physical is doing

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

float temp;
int tempPin = 0;

unsigned long interval=5000;  // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.

int buttonPin = 7;
boolean currentState = LOW;//stroage for current button state
boolean lastState = LOW;//storage for last button state
boolean ledState = LOW;//storage for the current state of the LED (off/on)

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte server[] = { 192, 168, 0, 100 };
byte ip[]     = { 192, 168, 0, 120 };


EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);


LiquidCrystal_I2C    lcd(0x27,2,1,0,4,5,6,7); // 0x27 is the I2C bus address for an unmodified backpack


byte bulb[8] = {
    0b01110,
    0b10001,
    0b10001,
    0b10001,
    0b01110,
    0b01010,
    0b01110,
    0b00100
};

byte plug[8] = {
    0b01010,
    0b01010,
    0b11111,
    0b10001,
    0b10001,
    0b01110,
    0b00100,
    0b00100
};

void callback(char* topic, byte* payload, unsigned int length) {
Serial.println("Callback");
Serial.print("Topic:");
Serial.println(topic);
Serial.print("Length:");
Serial.println(length);
Serial.print("Payload:");
Serial.write(payload,length);
Serial.println();

  if (strcmp(topic,"/testsw/1")==0) { 
   if (payload[0] == '0') 
    {
    digitalWrite(4, LOW);
    lcd.home();
    lcd.clear();
    lcd.write((uint8_t)1);
    lcd.print ("Turning Fan OFF");
    delay(100);
    client.publish("/testsw/1/state","0");
    } 
    else if (payload[0] == '1') 
    {
    digitalWrite(4, HIGH);
    lcd.home();
    lcd.clear();
    lcd.write((uint8_t)1);
    lcd.print ("Turning Fan ON");
    delay(100);
    client.publish("/testsw/1/state","1");
    }
   } 

  if (strcmp(topic,"/testsw/2")==0) { 
   if (payload[0] == '0') 
    {
    digitalWrite(5, LOW);
    lcd.home();
    lcd.clear();
    lcd.write((uint8_t)1);
    lcd.print ("Turning Light OFF");
    delay(100);
    client.publish("/testsw/2/state","0");
    } 
    else if (payload[0] == '1') 
    {
    digitalWrite(5, HIGH);
    lcd.home();
    lcd.clear();
    lcd.write((uint8_t)1);
    lcd.print ("Turning Light ON");
    delay(100);
    client.publish("/testsw/2/state","1");
    }
   } 


}

void setup()
{
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);//this time we will set the pin as INPUT
  digitalWrite(buttonPin, HIGH);
  lcd.begin (20,4); // for 16 x 2 LCD module
  lcd.createChar(0, bulb);
  lcd.createChar(1, plug);
  lcd.home(); // set cursor to 0,0
  lcd.print(" Starting  "); 
  delay(1000);
  Ethernet.begin(mac, ip);
    lcd.home();
    lcd.clear();
    lcd.print("Ethernet Connected"); 
    
  
  if (client.connect("arduinoClient")) {
    lcd.home();
    lcd.clear();
    lcd.print("MTQQ Connected");
    client.publish("outTopic","hello world");
    client.subscribe("/testsw/#");
  }
  pinMode(4, OUTPUT);
  digitalWrite(4, LOW);
  pinMode(5, OUTPUT);
  digitalWrite(5, LOW);

}

void loop()
{
  client.loop();
  
   if ((unsigned long)(millis() - previousMillis) >= interval) {
      previousMillis = millis();
      temp = analogRead(tempPin);
      temp = temp * 0.48828125;
      Serial.print("TEMPERATURE = ");
      Serial.print(temp);
      Serial.print("*C");
      Serial.println();
    
      char temperature[10];
      dtostrf(temp,4,3,temperature);

      client.publish("/home/1/ard2/s1/state",temperature);
   }
   

  currentState = digitalRead(buttonPin);
  if (currentState == HIGH && lastState == LOW){//if button has just been pressed
    Serial.println("pressed");
    delay(10);//crude form of button debouncing
    
    //toggle the state of the LED
    if (ledState == HIGH){
      digitalWrite(4, LOW);
      ledState = LOW;
      client.publish("/testsw/1/state","0");

    } else {
      digitalWrite(4, HIGH);
      ledState = HIGH;
       client.publish("/testsw/1/state","1");

    }
  }
  
  lastState = currentState;

}