The STM32 instances come with support for Platform IO Core (CLI). We will be using it for working on our projects. To know more about Platform IO Core (CLI) and the different commands go to the Platform IO documentation.
First, we need to initialise a new project using Platform IO. Let's create a new folder called Smart-Home which will hold all our code related to the project and then open the newly created folder in the terminal. Use the following commands:
Now we will initialise a new project using Platform IO. Type the following command in the terminal:
pioprojectinit--boardnucleo_f411re
The pio project init command is used to initialise the project. Then we need to specify the board which we want to use with the --board flag.
Once the project init command has run successfully, we will see some new folders inside the Smart-Home folder. We will store the files related to the project in the src folder.
After running the project init command, if you can't see the new files, you may have to reload the project files by clicking on PROJECT in the File Explorer pane.
Create a new file called main.cpp inside the src folder. This file will hold the code for the Smart Home Control program. Click on the main.cpp file to open it up in our code editor. Now, paste the following code inside the main.cpp file.
#include<Arduino.h>#include"Adafruit_MQTT.h"#include"Adafruit_MQTT_Client.h"#include<Ethernet.h>#include<EthernetClient.h>#include<Wire.h>/************************* Ethernet Client Setup *****************************/byte mac[]= { 0xDE,0xAD,0xBE,0xEF,0xFE,0xED };IPAddress ip(172,17,0,2);IPAddress myDns(8,8,8,8);/************************* Adafruit.io Setup *********************************/#defineAIO_SERVER"io.adafruit.com"#defineAIO_SERVERPORT1883#defineAIO_USERNAME"yourusername" //Replace this with your username#defineAIO_KEY"youradafruitiokey" //Replace this with your Adafruit IO key/************ Global State (you don't need to change this!) ******************///Set up the ethernet clientEthernetClient client;Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);// You don't need to change anything below this line!#definehalt(s) { Serial.println(F( s )); while(1); }/****************************** Feeds ***************************************/// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>Adafruit_MQTT_Publish light =Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/light");Adafruit_MQTT_Subscribe lamp =Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/lamp");/************************* APDS Driver code *********************************/class APDS9301 {public:boolbegin(int addr =0x29) {Wire.begin(); i2cAddr = addr;if (!setPower(true)) {returnfalse; }if (!setTiming(true,0)) {returnfalse; }returntrue; }boolsetPower(bool on) { byte regVal = (on ? REG_CONTROL_POWER_ON :0);returnsetReg(REG_CONTROL, regVal); }boolsetTiming(bool highGain,int integration) { byte regVal;if (highGain) { regVal = REG_TIMING_GAIN_16; gain =1; }else { regVal = REG_TIMING_GAIN_1; gain =1/16.0; }switch (integration) {case0: regVal |= REG_TIMING_INTEGRATE_13_7MS;this->integration = TIMING_SCALE_13_7MS;break;case1: regVal |= REG_TIMING_INTEGRATE_101MS;this->integration = TIMING_SCALE_101MS;break;default: regVal |= REG_TIMING_INTEGRATE_402MS;this->integration = TIMING_SCALE_402MS;break; }returnsetReg(REG_TIMING, regVal); }boolreadLux(float*lux) {uint16_t ch0, ch1;if (!getReg16(REG_DATA0LOW,&ch0)||!getReg16(REG_DATA1LOW,&ch1)) {returnfalse; }*lux =calcLux(ch0, ch1);returntrue; }private:boolsetReg(int reg, byte val) {Wire.beginTransmission(i2cAddr);int size =Wire.write(reg | REG_COMMAND_CMD);if (size ==1) {Wire.write(val); }if ((Wire.endTransmission() !=0) || (size !=1)) {returnfalse; }returntrue; }boolgetReg16(int reg,uint16_t*val) {Wire.beginTransmission(i2cAddr);int size =Wire.write(reg | REG_COMMAND_CMD | REG_COMMAND_WORD);if ((Wire.endTransmission() !=0) || (size !=1)) {returnfalse; }if (Wire.requestFrom(i2cAddr,2) !=2) {returnfalse; } byte lsb =Wire.read();*val =Wire.read();*val = (*val <<8) | lsb;returntrue; }floatcalcLux(uint16_t ch0,uint16_t ch1) {float ch0f = ch0 / gain / integration;float ch1f = ch1 / gain / integration;if (ch0f ==0) {return0; }float d = ch1f / ch0f;if (d <=0.5) {return (0.0304* ch0f -0.062* ch0f *pow(d,1.4)); }elseif (d <=0.61) {return (0.0224* ch0f -0.031* ch1f); }elseif (d <=0.8) {return (0.0128* ch0f -0.0153* ch1f); }elseif (d <=1.3) {return (0.00146* ch0f -0.00112* ch1f); }else {return0; } }staticconst byte REG_CONTROL =0x00;staticconst byte REG_TIMING =0x01;staticconst byte REG_THRESHLOWLOW =0x02;staticconst byte REG_THRESHLOWHIGH =0x03;staticconst byte REG_THRESHHIGHLOW =0x04;staticconst byte REG_THRESHHIGHHIGH =0x05;staticconst byte REG_INTERRUPT =0x06;staticconst byte REG_CRC =0x08;staticconst byte REG_ID =0x0A;staticconst byte REG_DATA0LOW =0x0C;staticconst byte REG_DATA0HIGH =0x0D;staticconst byte REG_DATA1LOW =0x0E;staticconst byte REG_DATA1HIGH =0x0F;staticconst byte REG_COMMAND_CMD =1<<7;staticconst byte REG_COMMAND_CLEAR =1<<6;staticconst byte REG_COMMAND_WORD =1<<5;staticconst byte REG_CONTROL_POWER_ON =0x03;staticconst byte REG_TIMING_GAIN_1 =0<<4;staticconst byte REG_TIMING_GAIN_16 =1<<4;staticconst byte REG_TIMING_START_CYCLE =1<<3;staticconst byte REG_TIMING_INTEGRATE_13_7MS =0;staticconst byte REG_TIMING_INTEGRATE_101MS =1;staticconst byte REG_TIMING_INTEGRATE_402MS =2;static constexpr float TIMING_SCALE_13_7MS =0.034;static constexpr float TIMING_SCALE_101MS =0.252;static constexpr float TIMING_SCALE_402MS =1;int i2cAddr;float gain;float integration;};APDS9301 apds9301;/*************************** Sketch Code ************************************/voidsetup() {Wire.begin();Serial.begin(115200);pinMode(7, OUTPUT);apds9301.begin();Serial.println(F("Smart Bulb with MQTT Dash"));// Initialise the ClientSerial.print(F("\nInit the Client..."));Ethernet.begin(mac, ip, myDns);delay(1000); //give the ethernet a second to initializemqtt.subscribe(&lamp);}// Function to connect and reconnect as necessary to the MQTT server.// Should be called in the loop function and it will take care if connecting.voidMQTT_connect() {int8_t ret;// Stop if already connected.if (mqtt.connected()) {return; }Serial.print("Connecting to MQTT... ");while ((ret =mqtt.connect()) !=0) { // connect will return 0 for connectedSerial.println(mqtt.connectErrorString(ret));Serial.println("Retrying MQTT connection in 5 seconds...");mqtt.disconnect();delay(5000); // wait 5 seconds }Serial.println("MQTT Connected!");}voidloop() {// Ensure the connection to the MQTT server is alive (this will make the first// connection and automatically reconnect when disconnected). See the MQTT_connect// function definition further below.MQTT_connect();//Get Lux values from APDS9301float lux; if (apds9301.readLux(&lux)) {Serial.println("Luminosity: "+ String(lux) +" lux"); }else {Serial.println("Cannot measure luminosity!"); }// Now we can publish stuff!Serial.print(F("\nSending lux value: "));Serial.print(lux);Serial.print("...");if (!light.publish(lux++)) {Serial.println("Lux Failed"); } else {Serial.println("Lux OK!"); } Adafruit_MQTT_Subscribe *subscription;while ((subscription =mqtt.readSubscription(1000))) {if (subscription ==&lamp) {Serial.print(F("Got: "));char*received = (char*) lamp.lastread;Serial.println(received);Serial.println(lamp.lastread[0]);if (lamp.lastread[0] ==49) {digitalWrite(7, HIGH);Serial.println(F("Lamp is now on")); }elseif (lamp.lastread[0] ==48) {digitalWrite(7, LOW);Serial.println(F("Lamp is now off")); } } }// ping the server to keep the mqtt connection aliveif (!mqtt.ping()) {mqtt.disconnect(); }delay(7000);}
In the above code, replace "yourusername" with your Adafruit IO username and "youradafruitiokey", with your Adafruit IO key which is present under My Key in Adafruit IO.
Before we can compile our code, we need to install a few libraries. First let's search for the Adafruit MQTT library. Go to your terminal and type:
pio lib search Adafruit MQTT
Platform IO will now search for the relevant libraries and provide us the results. Here we can see that we got the library we were looking for. We can see the Library ID at the top, in this case it is 1092. We will use this ID to install the library.
Type the following command in the terminal:
pio lib install 1092
This will install the Adafruit MQTT Library along with all of it's dependencies. Now we need to install the Ethernet library. Follow the same steps as before to install it via Platform IO.
piolibsearchEthernet#This is optionalpiolibinstall872
Now we are ready to compile our code. Save the main.cpp file. We will again use Platform IO to compile our code. Go to your terminal and type the following command.
pio run
The first time this command is run, Platform IO will download and install the relevant framework and toolchains required for the STM32. This process will take a few seconds.
Now Platform IO will compile our code and output a firmware.bin file. We need to copy this firmware file from the .pio/build/nucleo_f411re to /workspace. Usually you would need to use the cp command, but we have created a custom command called load-firmware for ease of use. Just write the following command and the firmware.bin file will be copied to the workspace folder.
load-firmware
Once we have copied the firmware.bin file, all we need to do is to reset the STM32 by pressing the red button above the STM32.
After the reset, the STM32 will load the new firmware, and we should have a remote control that can be configured to work with any smart home gadget.
You can decrease the delay in the void loop to decrease the time between subsequent messages.