Alexa can speak with iot devices (bulbs, switches, …) directly without creating any skill. Recently I’ve discoverer the library fauxmoesp to use a ESP32 as a virtual device and use it with Alexa.
I want to create a simple example with my M5Stack (it’s basically one ESP32 with an screen). It’s pretty straightforward to do it.
Here the firmware that I deploy to my device
Then I only need to pair my virtual device (in this case “my device”) to my compatible Alexa Device (In my case one echo spot). We can do it with the Alexa device’s menu or simply saying “Alexa discover devices”. Then I’ve got my iot device paired to my Alexa and I can say something like: “Alexa, switch on my device”, “Alexa, switch off my device” or “Alexa, set my device at 50%”
Today I want to keep on with the previous example. This time I want to create one Alexa skill that listen to external events. The example that I’ve build is the following one:
I’ve got one ESP32 with a proximity sensor (one HC-SR04) that is sending the distance captured each 500ms to a MQTT broker (a mosquitto server).
I say “Alexa, use event demo” then Alexa tell me to put my hand close to the sensor and it will tell me the distance.
The process is similar to the previous example. There’s a GadgetInterceptor to find the endpointId of my Raspberry Pi. But now the Raspberry Pi must emit to the event to the skill, not the skill to the event. Now my rpi’s python script is a little bit more complicated. We need to start the main loop for the Alexa Gadget SDK but also we need to start another loop listening to a mqtt event. We need to use threads as we see in a previous post. That’s the script that I’m using.
I must admit this post is just an excuse to play with Grafana and InfluxDb. InfluxDB is a cool database especially designed to work with time series. Grafana is one open source tool for time series analytics. I want to build a simple prototype. The idea is:
One Arduino device (esp32) emits a MQTT event to a mosquitto server. I’ll use a potentiometer to emulate one sensor (Imagine here, for example, a temperature sensor instead of potentiometer). I’ve used this circuit before in another projects
One Python script will be listening to the MQTT event in my Raspberry Pi and it will persist the value to InfluxDB database
I will monitor the state of the time series given by the potentiometer with Grafana
I will create one alert in Grafana (for example when the average value within 10 seconds is above a threshold) and I will trigger a webhook when the alert changes its state
One microservice (a Python Flask server) will be listening to the webhook and it will emit a MQTT event depending on the state
Another Arduino device (one NodeMcu in this case) will be listening to this MQTT event and it will activate a LED. Red one if the alert is ON and green one if the alert is OFF
The server
As I said before we’ll need three servers:
MQTT server (mosquitto)
InfluxDB server
Grafana server
We’ll use Docker. I’ve got a Docker host running in a Raspberry Pi3. The Raspberry Pi is a ARM device so we need docker images for this architecture.
ESP32
The Esp32 part is very simple. We only need to connect our potentiometer to the Esp32. The potentiometer has three pins: Gnd, Signal and Vcc. For signal we’ll use the pin 32.
We only need to configure our Wifi network, connect to our MQTT server and emit the potentiometer value within each loop.
The esp32 emits an event (“/pot”) with the value of the potentiometer. So we’re going to create a MQTT listener that listen to MQTT and persits the value to InfluxDB.
Grafana
In grafana we need to do two things. First to create one datasource from our InfluxDB server. It’s pretty straightforward to it.
Finally we’ll create a dashboard. We only have one time-serie with the value of the potentiometer. I must admit that my dasboard has a lot things that I’ve created only for fun.
Thats the query that I’m using to plot the main graph
SELECT
last("value") FROM "pot"
WHERE
time >= now() - 5m
GROUP BY
time($interval) fill(previous)
Here we can see the dashboard
And here my alert configuration:
I’ve also created a notification channel with a webhook. Grafana will use this web hook to notify when the state of alert changes
Webhook listener
Grafana will emit a webhook, so we’ll need an REST endpoint to collect the webhook calls. I normally use PHP/Lumen to create REST servers but in this project I’ll use Python and Flask.
We need to handle HTTP Basic Auth and emmit a MQTT event. MQTT is a very simple protocol but it has one very nice feature that fits like hat fits like a glove here. Le me explain it:
Imagine that we’ve got our system up and running and the state is “ok”. Now we connect one device (for example one big red/green lights). Since the “ok” event was fired before we connect the lights, our green light will not be switch on. We need to wait util “alert” event if we want to see any light. That’s not cool.
MQTT allows us to “retain” messages. That means that we can emit messages with “retain” flag to one topic and when we connect one device later to this topic, it will receive the message. Here it’s exactly what we need.
from flask import Flask
from flask import request
from flask_httpauth import HTTPBasicAuth
import paho.mqtt.client as mqtt
import json
client = mqtt.Client()
app = Flask(__name__)
auth = HTTPBasicAuth()
# http basic auth credentials
users = {
"user": "password"
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
@app.route('/alert', methods=['POST'])
@auth.login_required
def alert():
client.connect("docker", 1883, 60)
data = json.loads(request.data.decode('utf-8'))
if data['state'] == 'alerting':
client.publish(topic="/alert", payload="1", retain=True)
elif data['state'] == 'ok':
client.publish(topic="/alert", payload="0", retain=True)
client.disconnect()
return "ok"
if __name__ == "__main__":
app.run(host='0.0.0.0')
Nodemcu
Finally the Nodemcu. This part is similar than the esp32 one. Our leds are in pins 4 and 5. We also need to configure the Wifi and connect to to MQTT server. Nodemcu and esp32 are similar devices but not the same. For example we need to use different libraries to connect to the wifi.
This device will be listening to the MQTT event and trigger on led or another depending on the state
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
const int ledRed = 4;
const int ledGreen = 5;
// Wifi configuration
const char* ssid = "my_wifi_ssid";
const char* password = "my_wifi_password";
// mqtt configuration
const char* server = "192.168.1.111";
const char* topic = "/alert";
const char* clientName = "com.gonzalo123.nodemcu";
int value;
int percent;
String payload;
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void wifiConnect() {
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.print("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void mqttReConnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(clientName)) {
Serial.println("connected");
client.subscribe(topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
String data;
for (int i = 0; i < length; i++) {
data += (char)payload[i];
}
cleanLeds();
int value = data.toInt();
switch (value) {
case 1:
digitalWrite(ledRed, HIGH);
break;
case 0:
digitalWrite(ledGreen, HIGH);
break;
}
Serial.print("] value:");
Serial.println((int) value);
}
void cleanLeds() {
digitalWrite(ledRed, LOW);
digitalWrite(ledGreen, LOW);
}
void setup() {
Serial.begin(9600);
pinMode(ledRed, OUTPUT);
pinMode(ledGreen, OUTPUT);
cleanLeds();
Serial.println("start");
wifiConnect();
client.setServer(server, 1883);
client.setCallback(callback);
delay(1500);
}
void loop() {
Serial.print(".");
if (!client.connected()) {
mqttReConnect();
}
client.loop();
delay(500);
}
One saturday morning I was having a breakfast and I discovered face_recognition project. I started to play with the opencv example. I put my picture and, Wow! It works like a charm. It’s pretty straightforward to detect my face and also I can obtain the face landmarks. One of the landmark that I can get is the nose tip. Playing with this script I realized that with the nose tip I can determine the position of the face. I can see if my face is align to the center or if I move it to one side. As well as I have a new iot device (one ESP32) I wanted to do something with it. For example control a servo (SG90) and moving it from left to right depending on my face position.
First we have the main python script. With this script I detect my face, the nose tip and the position of my face. With this position I will emit an event to a mqtt broker (a mosquitto server running on my laptop).
import face_recognition
import cv2
import numpy as np
import math
import paho.mqtt.client as mqtt
video_capture = cv2.VideoCapture(0)
gonzalo_image = face_recognition.load_image_file("gonzalo.png")
gonzalo_face_encoding = face_recognition.face_encodings(gonzalo_image)[0]
known_face_encodings = [
gonzalo_face_encoding
]
known_face_names = [
"Gonzalo"
]
RED = (0, 0, 255)
GREEN = (0, 255, 0)
BLUE = (255, 0, 0)
face_locations = []
face_encodings = []
face_names = []
process_this_frame = True
status = ''
labelColor = GREEN
client = mqtt.Client()
client.connect("localhost", 1883, 60)
while True:
ret, frame = video_capture.read()
# Resize frame of video to 1/4 size for faster face recognition processing
small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
# Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
rgb_small_frame = small_frame[:, :, ::-1]
face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)
face_landmarks_list = face_recognition.face_landmarks(rgb_small_frame, face_locations)
face_names = []
for face_encoding, face_landmarks in zip(face_encodings, face_landmarks_list):
matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
name = "Unknown"
if True in matches:
first_match_index = matches.index(True)
name = known_face_names[first_match_index]
nose_tip = face_landmarks['nose_tip']
maxLandmark = max(nose_tip)
minLandmark = min(nose_tip)
diff = math.fabs(maxLandmark[1] - minLandmark[1])
if diff < 2:
status = "center"
labelColor = BLUE
client.publish("/face/{}/center".format(name), "1")
elif maxLandmark[1] > minLandmark[1]:
status = ">>>>"
labelColor = RED
client.publish("/face/{}/left".format(name), "1")
else:
status = "<<<<"
client.publish("/face/{}/right".format(name), "1")
labelColor = RED
shape = np.array(face_landmarks['nose_bridge'], np.int32)
cv2.polylines(frame, [shape.reshape((-1, 1, 2)) * 4], True, (0, 255, 255))
cv2.fillPoly(frame, [shape.reshape((-1, 1, 2)) * 4], GREEN)
face_names.append("{} {}".format(name, status))
for (top, right, bottom, left), name in zip(face_locations, face_names):
# Scale back up face locations since the frame we detected in was scaled to 1/4 size
top *= 4
right *= 4
bottom *= 4
left *= 4
if 'Unknown' not in name.split(' '):
cv2.rectangle(frame, (left, top), (right, bottom), labelColor, 2)
cv2.rectangle(frame, (left, bottom - 35), (right, bottom), labelColor, cv2.FILLED)
cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)
else:
cv2.rectangle(frame, (left, top), (right, bottom), BLUE, 2)
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
Now another Python script will be listening to mqtt events and it will trigger one event with the position of the servo. I know that this second Python script maybe is unnecessary. We can move its logic to esp32 and main opencv script, but I was playing with mqtt and I wanted to decouple it a little bit.
The event was one kind of Hackathon where a group of people meet together one day, to share our side projects and to work together (yes. We also have a lunch and beers also :). The format of the event is just a copy of the event that our colleagues from Bilbao called “El Comité“.
@ibaiimaz spoke about one project to create one collaborative pomodoro where the people of one team can share their status and see the status of the rest of the team. When I heard pomodoro and status I immediately thought in one servo moving a flag and some LEDs turning on and off. We had a project. @penniath and @tatai also joined us. We also had a team.
We had a project and we also had a deadline. We must show a working prototype at the end of the day. That means that we didn’t have too many time. First we decided the mockup of the project, reducing the initial scope (more ambitious) to fit it within our time slot. We discuss intensely for 10 minutes and finally we describe an ultra detailed blueprint. That’s the full blueprint of the project:
It was time to start working.
@penniath and @tatai worked in the Backend. It must be the responsible of the pomodoro timers, listen to MQTT events and create an API for the frontend. The backend also must provide a WebSockets interface to allow real time events within the frontend. They decided to use node and socket.io for the WebSockets. You can see the source code here.
@ibaiimaz started with the frontend. He decided to create an Angular web application listening to socket.io events to show the status of the pomodoro. You can see the source code here.
Finaly I worked with the hardware. I created a prototype with one ESP32, two RGB LEDs, one button, one servo and a couple of resistors.
That’s the source code.
#include <WiFi.h>
#include <PubSubClient.h>
int redPin_g = 19;
int greenPin_g = 17;
int bluePin_g = 18;
int redPin_i = 21;
int greenPin_i = 2;
int bluePin_i = 4;
#define SERVO_PIN 16
const int buttonPin = 15;
int buttonState = 0;
int channel = 1;
int hz = 50;
int depth = 16;
const char* ssid = "SSID";
const char* password = "password";
const char* server = "192.168.1.105";
const char* topic = "/pomodoro/+";
const char* clientName = "com.gonzalo123.esp32";
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void wifiConnect() {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("*");
}
Serial.print("WiFi connected: ");
Serial.println(WiFi.localIP());
}
void mqttReConnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(clientName)) {
Serial.println("connected");
client.subscribe(topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
String data;
for (int i = 0; i < length; i++) {
data += (char)payload[i];
}
int value = data.toInt();
if (strcmp(topic, "/pomodoro/gonzalo") == 0) {
Serial.print("[gonzalo]");
switch (value) {
case 1:
ledcWrite(1, 3400);
setColor_g(0, 255, 0);
break;
case 2:
setColor_g(255, 0, 0);
break;
case 3:
ledcWrite(1, 6400);
setColor_g(0, 0, 255);
break;
}
} else {
Serial.print("[ibai]");
switch (value) {
case 1:
setColor_i(0, 255, 0);
break;
case 2:
setColor_i(255, 0, 0);
break;
case 3:
setColor_i(0, 0, 255); // green
break;
}
}
Serial.print("] value:");
Serial.println(data);
}
void setup()
{
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(redPin_g, OUTPUT);
pinMode(greenPin_g, OUTPUT);
pinMode(bluePin_g, OUTPUT);
pinMode(redPin_i, OUTPUT);
pinMode(greenPin_i, OUTPUT);
pinMode(bluePin_i, OUTPUT);
ledcSetup(channel, hz, depth);
ledcAttachPin(SERVO_PIN, channel);
wifiConnect();
client.setServer(server, 1883);
client.setCallback(callback);
delay(1500);
}
void mqttEmit(String topic, String value)
{
client.publish((char*) topic.c_str(), (char*) value.c_str());
}
void loop()
{
if (!client.connected()) {
mqttReConnect();
}
client.loop();
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
mqttEmit("/start/gonzalo", (String) "3");
}
delay(200);
}
void setColor_i(int red, int green, int blue)
{
digitalWrite(redPin_i, red);
digitalWrite(greenPin_i, green);
digitalWrite(bluePin_i, blue);
}
void setColor_g(int red, int green, int blue)
{
digitalWrite(redPin_g, red);
digitalWrite(greenPin_g, green);
digitalWrite(bluePin_g, blue);
}
The MQTT server (a mosquitto server) was initially running in my laptop but as well as I had one Raspberry Pi Zero also in my bag we decided to user the Pi Zero as a server and run mosquitto MQTT server with Raspbian. Everything is better with a Raspberry Pi. @tatai helped me to set up the server.
Here you can see the prototype in action
That’s the kind of side projects that I normally create alone but definitely it’s more fun to do it with other colleagues even it I need to wake up early one Saturday morning.
I’ve been playing with MQTT in previous posts. Today I want to build a simple dashboard. Basically because I’ve got a 3.5inch display for my Raspberry Py and I want to use it. The idea is set up my Rasperry Pi as a web kiosk and display the MQTT variables in real time using websockets. Let’s start.
Set up Raspberry Pi as a web kiosk is pretty straightforward. You only need to follow instructions detailed here. Now we will prepare the MQTT inputs. Today we’re going to reuse one example of previous post. A potentiometer controlled by a nodemcu microcontroller connected to our MQTT server via Wifi.
We also will build another circuit using a Arduino board and a ethernet Shield.
With this circuit we’ll register the temperature (using a LM35 temperature sensor), a photo resistor (CDS) to show the light level and a relay to switch on/off a light bulb. The Idea of the circuit is emit the temperature and light level to mosquitto mqtt server and listen to switch status form mqtt server to fire the relay. That’s the arduino code
Now we’re going to work with dashboard. This days I’m working with OpenUI5 within various projects and because of that we’ll use this library to build the dashboard. we’ll build something like this:
I’ve got a new Arduino board (Arduino nano) and I want to hack a little bit. Today I want to play with IR receiver. My idea is to use my TV’s remote and switch on/off one bedside lamp, using one relay. It’s a simple Arduino program. First we need to include de IRremote library.
#include <IRremote.h>
#define IR 11
#define RELAY 9
IRrecv irrecv(IR);
IRsend irsender;
decode_results results;
unsigned long code;
void setup()
{
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, LOW);
irrecv.blink13(true);
irrecv.enableIRIn();
}
void loop() {
if (irrecv.decode(&results)) {
unsigned long current = results.value;
if (current != code) {
code = current;
switch (code) {
case 3772833823:
digitalWrite(RELAY, HIGH);
break;
case 3772829743:
digitalWrite(RELAY, LOW);
break;
}
}
irrecv.resume();
delay(100);
}
}
Normally IR receivers have three pins. Vcc (5V), Gnd and signal. We only need to connect the IR receiver to our Arduino and see which hex codes uses our TV’s remote. Then we only need to fire our relay depending on the code.
These days I’m playing with IoT. Today I want to use MQTT protocol to comunicate between different devices. First I’ve start a mqtt broker in my Laptop. For testing I’ll use mosquitto server. In production we can use RabbitMQ or even a 3party server such as iot.eclipse.org or even Amazon’s IoT service.
The idea is emit one value with one device, and listen this value whit the rest of devices and perform one action depending on that value. For example I will use one potentiometer connected to on NodeMcu micro controller.
This controller will connect to the mqtt broker and will emit the value of the potentiometer (reading the analog input) into one topic (called “potentiometer”). We can code our NodeMcu with Lua but I’m more confortable with C++ and Arduino IDE. First I need to connect to my Wifi and then connect to broker and start emmiting potentiometer’s values
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
// Wifi configuration
const char* ssid = "MY_WIFI_SSID";
const char* password = "my_wifi_password";
// mqtt configuration
const char* server = "192.168.1.104";
const char* topic = "potentiometer";
const char* clientName = "com.gonzalo123.nodemcu";
int value;
int percent;
String payload;
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void wifiConnect() {
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.print("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (client.connect(clientName)) {
Serial.print("Connected to MQTT broker at ");
Serial.print(server);
Serial.print(" as ");
Serial.println(clientName);
Serial.print("Topic is: ");
Serial.println(topic);
}
else {
Serial.println("MQTT connect failed");
Serial.println("Will reset and try again...");
abort();
}
}
void mqttReConnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientName)) {
Serial.println("connected");
client.subscribe(topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(9600);
client.setServer(server, 1883);
wifiConnect();
delay(10);
}
void loop() {
value = analogRead(A0);
percent = (int) ((value * 100) / 1010);
payload = (String) percent;
if (client.connected()) {
if (client.publish(topic, (char*) payload.c_str())) {
Serial.print("Publish ok (");
Serial.print(payload);
Serial.println(")");
} else {
Serial.println("Publish failed");
}
} else {
mqttReConnect();
}
delay(200);
}
Now we will use another Arduino (with a ethernet shield).
We’ll move one servomotor depending to NodeMcu’s potentiomenter value. This Arduino only needs to listen to MQTT’s topic and move the servo.
#include <SPI.h>
#include <Servo.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#define SERVO_CONTROL 9
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
Servo servo;
EthernetClient ethClient;
// mqtt configuration
const char* server = "192.168.1.104";
const char* topic = "potentiometer";
const char* clientName = "com.gonzalo123.arduino";
PubSubClient client(ethClient);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] angle:");
String data;
for (int i = 0; i < length; i++) {
data += (char)payload[i];
}
double angle = ((data.toInt() * 180) / 100);
constrain(angle, 0, 180);
servo.write((int) angle);
Serial.println((int) angle);
}
void mqttReConnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientName)) {
Serial.println("connected");
client.subscribe(topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup()
{
Serial.begin(9600);
client.setServer(server, 1883);
client.setCallback(callback);
servo.attach(SERVO_CONTROL);
if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
}
delay(1500); // Allow the hardware to sort itself out
}
void loop()
{
if (!client.connected()) {
mqttReConnect();
}
client.loop();
}
Finally we’ll use one Raspberry Pi with a Sense Hat and we’ll display with its led matrix different colors and dots, depending on the NodeMcu’s value. In the same way than the Arduino script here we only need to listen to the broker’s topic and perform the actions with the sense hat. Now with Python
import paho.mqtt.client as mqtt
from sense_hat import SenseHat
sense = SenseHat()
sense.clear()
mqttServer = "192.168.1.104"
red = [255, 0, 0]
green = [0, 255, 0]
yellow = [255, 255, 0]
black = [0, 0, 0]
def on_connect(client, userdata, rc):
print("Connected!")
client.subscribe("potentiometer")
def on_message(client, userdata, msg):
value = (64 * int(msg.payload)) / 100
O = black
if value < 21:
X = red
elif value < 42:
X = yellow
else:
X = green
sense.set_pixels(([X] * value) + ([O] * (64 - value)))
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(mqttServer, 1883, 60)
client.loop_forever()
Today I want to use the NFC tag reader module with my Arduino. The idea is build a simple prototype to read NFC tags and validate them against a remote server (for example a node tcp server). Depending on the tag we’ll trigger one digital output or another. In the example we’ll connect leds to those outputs, but in the real life we can open door or something similar.
We’ll use a MFRC522 module. It’s a cheap Mifare RFID/NFC tag reader and writer.
MFRC522 Connection:
sda: 10 (*) -> 8
sck: 13
Mosi: 11
Miso: 12
Rq: —
Gnd: Gnd
Rst: 9
3.3V: 3.3V
In this example we’ll use a ethernet shield to connect our Arduino board to the LAN. We must take care with it. If we use ethernet shield with a MFRC522 there’s a SPI conflict (due to ethernet shield’s SD card reader). We need to use another SDA pin (here I’m using pin 8 instead of 10) and disable w5100 SPI before configure ethernet.
The easiest way to connect our Arduino board to our Raspberry Py is using the USB cable, but sometimes this communication is a nightmare, especially because there isn’t any clock signal to synchronize our devices and we must rely on the bitrate. There’re different ways to connect our Arduino and our Raspberry Py such as I2C, SPI and serial over GPIO. Today we’re going to speak about I2C, especially because it’s pretty straightforward if we take care with a couple of things. Let’s start.
I2C uses two lines SDA (data) and SCL (clock), in addition to GND (ground). SDA is bidirectional so we need to ensure, in one way or another, who is sending data (master or slave). With I2C only master can start communications and also master controls the clock signal. Each device has a 7bit direction so we can connect 128 devices to the same bus.
If we want to connect Arduino board and Raspberry Pi we must ensure that Raspberry Pi is the master. That’s because Arduino works with 5V and Raspberry Pi with 3.3V. That means that we need to use pull-up resistors if we don’t want destroy our Raspberry Pi. But Raspberry Pi has 1k8 ohms resistors to the 3.3 votl power rail, so we can connect both devices (if we connect other i2c devices to the bus they must have their pull-up resistors removed)
Thats all we need to connect our Raspberry pi to our Arduino board.
RPi SDA to Arduino analog 4
RPi SCL to Arduino analog 5
RPi GND to Arduino GND
Now we are going to build a simple prototype. Raspberry Pi will blink one led (GPIO17) each second and also will send a message (via I2C) to Arduino to blink another led. That’s the Python part
import RPi.GPIO as gpio
import smbus
import time
import sys
bus = smbus.SMBus(1)
address = 0x04
def main():
gpio.setmode(gpio.BCM)
gpio.setup(17, gpio.OUT)
status = False
while 1:
gpio.output(17, status)
status = not status
bus.write_byte(address, 1 if status else 0)
print "Arduino answer to RPI:", bus.read_byte(address)
time.sleep(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print 'Interrupted'
gpio.cleanup()
sys.exit(0)
And finally the Arduino program. Arduino also answers to Raspberry Pi with the value that it’s been sent, and Raspberry Pi will log the answer within console.
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
#define LED 13
int number = 0;
void setup() {
pinMode(LED, OUTPUT);
Serial.begin(9600);
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
Serial.println("Ready!");
}
void loop() {
delay(100);
}
void receiveData(int byteCount) {
Serial.print("receiveData");
while (Wire.available()) {
number = Wire.read();
Serial.print("data received: ");
Serial.println(number);
if (number == 1) {
Serial.println(" LED ON");
digitalWrite(LED, HIGH);
} else {
Serial.println(" LED OFF");
digitalWrite(LED, LOW);
}
}
}
void sendData() {
Wire.write(number);
}