MQTT Controlled RF Outlets

In the last post, I briefly went through how I sniffed and was able to control RF controlled outlets. Now I have ported the code to the Raspberry Pi and also written a short BASH MQTT daemon that enables me to controll these switches using MQTT.

All the code is available here on my Github, here.

Let’s begin!

In the last post, I used the RCSwitch library, which is already compatible with the Raspberry Pi! However, it relies on wiringPi, which is a library to utilize the GPIO pins of the RPi. The pin numbering varies a lot between libraries and the actual physical layout on the Pi, but luckily someone made this nifty website: pinout.xyz. In my project, I used the physical pin 13, which maps to pin 2 in wiringPi or pin 27 on the Broadcom chip itself.

Below is a short program for transmitting data. E.g. ./send 1234

Program for transmitting

/* 
 * Send a RF data through a transmitter module connected to 
 * TRANS_PIN-pin on the Raspberry Pi 
 *  
 *	Example: 
 * 		./send 1234
 */
#include "rc-switch-master/RCSwitch.h"
#include <stdio.h> // printf, fgets
#include <stdlib.h> // exit

RCSwitch trans;
        
int main(int argc, char *argv[]) {
  if(argc < 2) {
    printf("No command specified.\n");
    exit(EXIT_FAILURE);
  }
  
  /* Change these to fit your RF outlets */ 
  int TRANS_PIN = 2;
  int PROTOCOL = 4;
  int PULSE_LENGTH = 380;
  int DATA_LENGTH = 24

  /* Setup wiringPi */
  if(wiringPiSetup() == -1) {
    printf("wiringPi failed. Exiting...\n");
    exit(EXIT_FAILURE);
  }
 
  trans = RCSwitch();
  trans.enableTransmit(TRANS_PIN);
  trans.setProtocol(PROTOCOL);
  trans.setPulseLength(PULSE_LENGTH);
 
  trans.send(atoi(argv[1]), DATA_LENGTH);
  
  exit(EXIT_SUCCESS);
}

But that only takes us half way! I wanted to control the outlets using the MQTT protocol.

I’m running the Mosquitto broker, which also comes with a publish and subscribe client. So it was relatively easy to construct a small BASH MQTT daemon.

BASH MQTT Daemon

#!/bin/bash

# Set the topic to subscribe to. 
SUB_TOPIC="cmnd/switches/+"

# MQTT credentials 
USER="<replace me>"
PW="<replace me>"

# Declare the commands here. 
# If we recieve 'cmnd/switches/A ON' the script executes './send 11840172' 
# The code was sniffed from the remote using 'ProtocolAnalyzeDemo' from this
# fork of rc-switch: https://github.com/Martin-Laclaustra/rc-switch/tree/protocollessreceiver

# This is an associative array. 
declare -A COMMANDS
COMMANDS["A ON"]=11840172
COMMANDS["A OFF"]=12552332
COMMANDS["B ON"]=11949797
COMMANDS["B OFF"]=11639189
COMMANDS["C ON"]=12284094
COMMANDS["C OFF"]=12502382
COMMANDS["D ON"]=11639191
COMMANDS["D OFF"]=12379911

# Just some pretty colorized output. 
RED='\e[31m'
GREEN='\e[32m'
YELLOW='\e[93m'
DEFAULT='\e[39m'

while read MSG;
do
    # SWITCH=$(sed -e 's/.*\/\([A-B]\).*/\1/' <<< $MSG)
    # COMMAND=$(sed -e 's/.* \(\w*$\).*/\1/' <<< $MSG)
    
    # Extract everything after the last slash in the MQTT command. 
    COMMAND=$(sed -e 's/.*\/\(.*\)/\1/' <<< $MSG) 
    echo -en $YELLOW$(date)':' $DEFAULT$MSG;
    
    # If the received command was valid, execute ./send with the approriate 
    # decimal command. 
    if [[ ${COMMANDS[$COMMAND]} ]]; then     
        echo -e $GREEN' ✔︎' $DEFAULT
        ./send ${COMMANDS[$COMMAND]}
    else 
        echo -e $RED' ✘ No such command' $DEFAULT
    fi

# Setup the subscription using mosquitto_sub
done < <(mosquitto_sub -u ${USER} -P ${PW} -t ${SUB_TOPIC} -q 1 -v)

Then, in order to make it start automatically on boot I had to make a service file for systemd to read. It should be placed in /etc/systemd/system. In order for systemd to see the new service, we need to reload it.
sudo systemctl daemon-reload
and then enable
sudo systemctl enable mqttexec.service
and start
sudo systemctl start mqttexec.service.

MQTTExec.service

#!/bin/bash

# Set the topic to subscribe to. 
SUB_TOPIC="cmnd/switches/+"

# MQTT credentials 
USER="<replace me>"
PW="<replace me>"

# Declare the commands here. 
# If we recieve 'cmnd/switches/A ON' the script executes './send 11840172' 
# The code was sniffed from the remote using 'ProtocolAnalyzeDemo' from this
# fork of rc-switch: https://github.com/Martin-Laclaustra/rc-switch/tree/protocollessreceiver

# This is an associative array. 
declare -A COMMANDS
COMMANDS["A ON"]=11840172
COMMANDS["A OFF"]=12552332
COMMANDS["B ON"]=11949797
COMMANDS["B OFF"]=11639189
COMMANDS["C ON"]=12284094
COMMANDS["C OFF"]=12502382
COMMANDS["D ON"]=11639191
COMMANDS["D OFF"]=12379911

# Just some pretty colorized output. 
RED='\e[31m'
GREEN='\e[32m'
YELLOW='\e[93m'
DEFAULT='\e[39m'

while read MSG;
do
    # SWITCH=$(sed -e 's/.*\/\([A-B]\).*/\1/' <<< $MSG)
    # COMMAND=$(sed -e 's/.* \(\w*$\).*/\1/' <<< $MSG)
    
    # Extract everything after the last slash in the MQTT command. 
    COMMAND=$(sed -e 's/.*\/\(.*\)/\1/' <<< $MSG) 
    echo -en $YELLOW$(date)':' $DEFAULT$MSG;
    
    # If the received command was valid, execute ./send with the approriate 
    # decimal command. 
    if [[ ${COMMANDS[$COMMAND]} ]]; then     
        echo -e $GREEN' ✔︎' $DEFAULT
        ./send ${COMMANDS[$COMMAND]}
    else 
        echo -e $RED' ✘ No such command' $DEFAULT
    fi

# Setup the subscription using mosquitto_sub
done < <(mosquitto_sub -u ${USER} -P ${PW} -t ${SUB_TOPIC} -q 1 -v)

I hope this helps someone 🙂

Written on March 3, 2018