Apple HomeKit on iOS with Arduino (ESP8266) through Raspberry Pi
Note: This post, and the previous one (part 1), are obsolete. They have been replaced by this one, offering a simpler method to get started. They are left here for reference.
Part 1 of this article explained how to install a HomeKit server on a Raspberry Pi. This will allow you to add new, DIY accessories that can receive commands from Siri.
Part 2 (this article) explains how to install an MQTT server that can be a “bridge” between Siri (through you HomeKit server) and you hardware.
MQTT is a communication protocol that will let you send and receive simple messages from one computer to another. You need one server a a number of clients. We will setup the server on our Raspberry Pi, but there are servers available publicly.
Install the MQTT server: Mosquitto
There are other MQTT servers available but this one works well and is easy to install.
sudo wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key sudo apt-key add mosquitto-repo.gpg.key cd /etc/apt/sources.list.d/ sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list sudo apt-get update sudo apt-get install mosquitto
This will add the mosquitto repo to your list, then the last instruction actually uses the standard apt-get install.
Next, install the Mosquitto clients to test your server (if you want). They are the actual commands to use your Raspberry Pi as an MQTT client.
sudo apt-get install mosquitto-clients
This link has many good pointers to configure the Mosquitto server to start and stop as a service, but this simple installation will be ok for testing.
Let’s test our mosquitto server. Open a new terminal window on your Raspberry Pi (or an SSH session if you are accesing it remotely) and type
mosquitto_sub -d -t hello/world
This will “subscribe” to the “hello” topic (-t), “world” sub-topic on your server (localhost). This can be ANYTHING you want. There is no real format and the / or /’s are optional. The terminal will be executing MQTT in “subscribe” (think if it as “receive” or “listen”) mode and will just wait for the proper incoming message, meaning with the proper topic.
Now we need to publish a message (-m) on the same topic (-t), but in a new terminal window (or SSH session):
mosquitto_pub -d -t hello/world -m "Hello from Terminal window 2!"
The first window should show the message
Client mosqsub/12234-raspberry received PUBLISH (d0, q0, r0, m0, 'hello/world', ... (29 bytes)) Hello from Terminal window 2!
In my environment, I have one MQTT server on a Raspberry Pi and messages coming and going from other Raspberry Pis and sensor equipped Arduinos.
A particular device can send or receive MQTT messages and can also do both at the same time.
EPS8266 Wifi Micro-controller
For this article, I’m using an Arduino type of micro-controller that has a Wifi stack. Someone has written an Arduino library that handles MQTT communications, and being Wifi, this Arduino also has a Wifi library taking care of communications.
I’m using an Adafruit Huzzah ESP8266 micro controller. It has Wifi on board and is compatible with the Arduino environment. It’s not strictly an arduino, and the processor is not the typical Atmel 328, but Adafruit has written everything you need to program it from the Arduino IDE. Any wifi-enabled Arduino could be used, but the the ESP8266 is dirt cheap (10$) and is very compact. Please use the link above to learn how to dowload the appropriate Arduino library and run some tests for Wifi connections.
Now, let’s test the ESP8266 with a simple sketch that will send a message on the topic “/hello”. The message is “world” and is sent every minute. The sketch will also listen to the topic “hello/world” and print incoming messages. So if everything goes well, it will print the message it just sent to the MQTT server!
/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic" every two seconds
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4+):
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
- Select your ESP8266 in "Tools -> Board"
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "default";
const char* password = "leborddulac";
const char* mqtt_server = "192.168.2.180";
const char* host = "hello/world"; //used to identify topic. This is the string of
// characcters used in the *_accessory.js file to identify the topic
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
digitalWrite(BUILTIN_LED, HIGH); // ...and turn if off (reversed logic for the esp8266)
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883); //connect to the mqtt server at address above
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String mypayload = " ";
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
mypayload[i] = (char)payload[i];
}
Serial.print(" Payload: ");
Serial.print(mypayload);
Serial.println();
String mytopic = String(topic);
if (mytopic == host) { // Is this the right Topic?
// Switch on the LED if the payload in "on"
//if ((char)payload[1] == 'n') { if (mypayload == statusOn) {
if (mypayload == statusOn) {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is acive low on the ESP-01)
//client.publish(host, "Powered");
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
//client.publish(host, "NOTPowered");
}
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("ESP8266Client")) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("#");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 60000) {
lastMsg = now;
++value;
snprintf (msg, 75, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}
Once you ESP8266 is communicating with your MQTT server, most of the hard work is done. You now have an Arduino type micro-controller linked to your MQTT network.
You could decide to go no further and not link this to HomeKit and Siri. In fact, most of my sensors use MQTT to communicate together on my Wifi network, and these sensors are connected to Arduino, Raspberry Pi and other computers. In a future article, I will talk about HomeKit in more details, and eventually I will explain my node-red setup and interface.
Leave a Reply