Philippe Libioulle
Published © GPL3+

Home Automation Orchestrator

A device that gathers information from various home automation agents and dispatches orders to those devices based on rules.

IntermediateFull instructions provided20 hours1,429
Home Automation Orchestrator

Things used in this project

Hardware components

DragonBoard 410c
Qualcomm DragonBoard 410c
×1
Seeed Studio Mezzanine sensor board
×1
AC/DC power supply (12v DC , 2A)
×1
LEd strip
×1
Seeed Studio Set of cables
×1
Ethernet over USB
×1
DC cable with jack
×1

Story

Read more

Code

Mezzanine code

Arduino
The goal is to listen to commands originating from the DragonBoard and to interpret those commands to control the 8 LEDs strip

Commands are formatted as per the following:

Fixed length messages, 10 bytes long

Byte Description

0 Always 0x02 (= begin of message)
1 Command
2-9 Parameters


Command Description Parameters

0x10 All OFF None (all 00)
0x20 Selftest None (all 00)
0x30 Setup one led Position, Color, Brightness
0x40 ProgressBar Progress, Color, Brightness


Position = 1 byte (1 = the first LED, starting from the left)
Color = 3 bytes (R, G & B)
Brightness = 1 byte, percentage, between 0 and 100
Progress = 1 byte, percentage between 0 and 100


Examples

0x02 0x30 0x04 0x00 0xFF 0x00 0xFF 0x00 0x00 0x00 = turn LED 4 to 100% green
0x02 0x40 0x50 0xFF 0x00 0x00 0xFF 0x00 0x00 0x00 = show 50% progress bar (i.e 4 LEDs) in 100% red
#include "Adafruit_NeoPixel.h"
#ifdef __AVR__
  #include <avr/power.h>
#endif

const int LEDCOUNT = 8;
const int ARRAYSIZE = 10;
const int TIMEOUT = 2000; //in millisec  

int inByte[ARRAYSIZE]= {0,0,0,0,0,0,0,0,0,0};    // for storing incoming serial bytes
int startByte = 0x02;                            // Every message begins with this
int i = 0;              

Adafruit_NeoPixel leds = Adafruit_NeoPixel(8, 5, NEO_GRB + NEO_KHZ800);

void setup()
{  
   Serial.begin(9600);        
   Serial.println(F("Begin of setup."));  
   leds.begin();
   leds.show();
   ledsTest();   
   delay(1000);  
   Serial.println(F("Setup completed, now waiting for new messages..."));   
}

void loop()
{  
   while (Serial.available() > 0)       
   {      
     if (receiveMessageFromDragon() == 0) // message received and compliant with message type definition
     {
        processCommand();  
        resetArray();     
     };          
  };
}

int receiveMessageFromDragon()
{
   long start_time = millis();  
   int currentIndex = 0;     
   resetArray(); 
   byte currentByte;     
      
   while (true)
   {
      if ((millis() - start_time) > TIMEOUT)  // we should get a complete message in a short period of time
      {
        Serial.println(F("Error - communication lost..."));
	return 2;
      };
      if (Serial.available() > 0)
      {
         currentByte = Serial.read();
         inByte[currentIndex] = currentByte;
                          
         printRawData(currentByte, currentIndex);
         
         if (currentIndex == 0 && currentByte != startByte)  // a new message should always start with the specified start byte
         {
            Serial.println(F("Error - message should start with 0x02..."));
	    return 2;
         }; 
         if (currentIndex > (ARRAYSIZE - 1) )   // message looks longer than expected
         {
            Serial.println(F("Error - message looks longer than expected..."));
            return 4; 
         };       
         if (currentIndex == (ARRAYSIZE - 1) ) // message has been received as expected
         {
            Serial.println(F("Message received..."));
            return 0;  // full message received
         }; 
         currentIndex = currentIndex + 1;  // just keep going with parsing         
      };
   };   
}

void resetArray()
{ 
   // Serial.println(F("Reset array"));
   for(int j=0;j<ARRAYSIZE;j++) 
   { 
      // Serial.print(j);
       inByte[j] = 0;
   };
   // Serial.println(F("Reset array completed"));
} 

void processCommand()
{  
   switch (inByte[1])
   {  
      case 0x10:
	    ledsReset();
        break;
	  case 0x20:
	    ledsTest();
        break;
	  case 0x30:
	    setupOneLed();
        break;
	  case 0x40:
	    showProgress();		
      default:
        Serial.println(F("Unknown command..."));	  
   };  
}

void ledsTest()
{  
  Serial.println(F("LED self test"));  
  for (int i=7; i>=0; i--)
  {  
     leds.setPixelColor(i, 0x00FF00);    // Full green 
     leds.show();
     delay(50);	 
  };
  for (int i=7; i>=0; i--)
  {  
     leds.setPixelColor(i, 0x000000);    // Full green 
     leds.show();    	 
  };    
}

void ledsReset()
{  
  Serial.println(F("LED reset"));
  for (int i=7; i>=0; i--)
  {  
     leds.setPixelColor(i, 0x000000);   // all OFF     	 
  }  
  leds.show();
}

void setupOneLed()
{  
  Serial.println(F("Setup one single LED"));
  leds.setPixelColor(inByte[2],inByte[3],inByte[4],inByte[5]);   // all OFF 
  leds.setBrightness(inByte[6]);  
  leds.show();  
} 

void showProgress()
{  
  Serial.println(F("Progress bar"));
  for (int i=7; i>=0; i--)
  {  
     leds.setPixelColor(i, 0x000000);   // all OFF     	 
  } 
  int upTo = map(inByte[2], 0, 100, 0, 7) - 1; 
  // Serial.println(upTo); 
  for (int i=7; i>=upTo; i--)
  {  
     leds.setPixelColor(i, inByte[3], inByte[4], inByte[5]);   
  }  
  leds.setBrightness(inByte[6]);
  leds.show();
} 

void printRawData(byte b, int index)
{
  Serial.print(F("Index = "));
  Serial.print(index);
  Serial.print(F(" Value = ["));
  Serial.print(b, HEX);   
  Serial.println(F("]"));  
}

Hello Arduino

Python
#!/usr/bin/env python

import serial, time

# This is the Publisher

uno = serial.Serial('/dev/tty96B0', 9600)
uno.write('')
time.sleep(5)

print('Off.')
uno.write('\x02')
uno.write('\x20')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')

time.sleep(10)

print('SelfTest')
uno.write('\x02')
uno.write('\x10')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')

time.sleep(10)

print('LED to GREEN %')
uno.write('\x02')
uno.write('\x30')
uno.write('\x04')
uno.write('\x00')
uno.write('\xFF')
uno.write('\x00')
uno.write('\xFF')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')

time.sleep(10)

print('Progress bar')
uno.write('\x02')
uno.write('\x40')
uno.write('\x50')
uno.write('\xFF')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')

Hello Broker

Python
just a simple test to publish a message to MQTT broker
#!/usr/bin/env python

import paho.mqtt.client as mqtt

# This is the Publisher

client = mqtt.Client()
print(client.connect("localhost",1883,60))
print(client.publish("topic/test", "Hello world!"));
client.disconnect();
print(0)

Smoke detected scenario

Python
A more complex scenario: system listens to messages sent by Smoke Detector, display a visual alert on the front panel and then publish a message back to MQTT broker, targeting my Insteon gateway
import serial, time, paho.mqtt.client as mqtt

message = 'ON'

def on_connect(mosq, obj, rc):
    mqttc.subscribe("GLX/FIRSTFLOOR/001/Fault/#")
    print("Connect rc: " + str(rc))
    print('LED 4 to GREEN 100 %')
    uno.write('\x02')
    uno.write('\x30')
    uno.write('\x04')
    uno.write('\x00')
    uno.write('\xFF')
    uno.write('\x00')
    uno.write('\xFF')
    uno.write('\x00')
    uno.write('\x00')
    uno.write('\xFF')

def on_message(mosq, obj, msg):
    global message
    print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
    message = msg.payload
    print('LED 5 to GREEN 100 %')
    uno.write('\x02')
    uno.write('\x30')
    uno.write('\x05')
    uno.write('\x00')
    uno.write('\xFF')
    uno.write('\x00')
    uno.write('\xFF')
    uno.write('\x00')
    uno.write('\x00')
    uno.write('\xFF')
    time.sleep(1)
    mqttc.publish("GLI/Gateway/ToDo","0A:26:D8:83:11:FF");

def on_publish(mosq, obj, mid):
    print("On publish - mid: " + str(mid))
    print('LED 5 OFF')
    uno.write('\x02')
    uno.write('\x30')
    uno.write('\x05')
    uno.write('\x00')
    uno.write('\x00')
    uno.write('\x00')
    uno.write('\xFF')
    uno.write('\x00')
    uno.write('\x00')
    uno.write('\xFF')

def on_subscribe(mosq, obj, mid, granted_qos):
    print("Subscribed: " + str(mid) + " " + str(granted_qos))

def on_log(mosq, obj, level, string):
    print(string)

uno = serial.Serial('/dev/tty96B0', 9600)
uno.write('')
time.sleep(5)

print('Off.')
uno.write('\x02')
uno.write('\x20')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\x00')
uno.write('\xFF')

mqttc = mqtt.Client()

# Assign event callbacks
mqttc.on_message = on_message
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_subscribe = on_subscribe

# Connect
mqttc.connect("localhost", 1883, 60)


# Continue the network loop
mqttc.loop_forever()

Credits

Philippe Libioulle

Philippe Libioulle

7 projects • 49 followers

Comments