Observations & Surprises
This project has been a very interesting journey researching a wide variety of invisible potential hazards, designing systems to measure invisible hazards, building wearable instrumentation and testing my environment to see what invisible hazards might be present.
It is probably obvious from the content of my blogs that I learned a lot, actually way too much to fit into a few blogs, but the big surprise for me was how much fun it was. I anticipated the usual thrill I get from designing things and making them work, but I did not foresee how much fun it would be to use the instrumentation to examine my environment. It is a bit like the first time you got to play with a magnifying glass – you just run around looking at absolutely everything in a new way. It was also surprising to me how many people around me took an interest and wanted to examine their own environments. Normally talking about my projects is a good way to elicit glazed looks of boredom, but with this project, so many people wanted to borrow instrumentation it was tough to hang onto it long enough to take my own measurements.
The Kit
I am very happy the EXP432P401R was the required processor module for this design challenge as I might not have discovered it otherwise. This module is a very powerful, very capable and cost-effective platform for applications like this and will definitely be a favourite choice for future projects. The development environment was very easy to learn and use, especially since there were good examples available for most of the functionality I wanted to implement.
The comprehensive kit of modules supplied with the challenge (thanks Texas Instruments and element14) really allowed a complete wireless instrument with LCD to be implemented without even having to use wires and cables. Normally building such a platform would be an ambitious undertaking on its own, but with these plug-and-play booster packs and existing software examples, it enables projects to start with a complete, highly functional system and go beyond just getting some computer hardware to work.
Highlights
I got to design a custom sensor booster pack and the clear documentation available from Texas Instruments allowed it to work flawlessly without rework, respin or modification. It is really worth taking the time to do the job well – the gratification (and relief ) is immense.
I also got to design many 3D printed parts, continuing my mechanical design learning journey.
It has been a long project with many little problems to overcome, but all the things I've learned and all the things I've accomplished in this project have made it a truly fabulous experience.
This is probably my last blog during this challenge as I have other projects that need attention, but you never know – I certainly will continue to work on the system and use it – the novelty has not worn off yet.
I did want to publish the software I used in the project - for completeness. However, I don't claim any kind of quality for the software, it lacks error checking and handling among other issues. One feature I didn't mention in my other blogs is if the right switch is held down during boot, the sensor system will run stand-alone, without WiFi.
IHEF Sensor MQTT Publishing Firmware
// Invisible Hazardous Environmental Factors (IHEF) Monitoring System // Gas sensor, UV measurement and MQTT publishing software // by Doug Wong // 2017 - 06 // rev 01 #include <SPI.h> #include <WiFi.h> #include <WifiIPStack.h> #include <Countdown.h> #include <MQTTClient.h> #include <OneMsTaskTimer.h> #include <LCD_SharpBoosterPack_SPI.h> #include <Wire.h> // network name also called SSID char ssid[] = "AndroidAP"; //network name - this should be altered for your system *** // network password char password[] = "aaaaaa"; //network password - this should be altered for your system *** // Cloud Settings #define MQTT_MAX_PACKET_SIZE 100 #define SERVERURLLEN 14 #define IOTFSERVER "xxx.xxx.x.xx" //server URL - this should be altered for your system *** char organization[] = ""; char typeId[] = "iotsample-ti-energia"; char pubtopic[] = "IHEF"; char deviceId[] = "000000000000"; char clientId[64]; uint8_t macOctets[6]; // DAS Variables LCD_SharpBoosterPack_SPI myScreen; int AlcPin = A11; //MQ3 - Alcohol int COPin = A14; //MQ7 - Carbo Monoxide int AQPin = A13; //MQ135 - Air Quality int CO2Pin = A8; //CO2 int UVPin = A9; //Ultraviolet Light int AlcValue = 0; //MQ3 - Alcohol int COValue = 0; //MQ7 - Carbo Monoxide int AQValue = 0; //MQ135 - Air Quality int CO2Value = 0; //CO2 int UVValue = 0; //Ultraviolet Light int AlcHpin = 31; //MQ3 Heater int COHpin = 38; //MQ7 Heater int AQHpin = 32; //MQ135 Heater String AlcStr; //string to display alcohol value String COStr; //string to display CO value String AQStr; //string to display air quality value String CO2Str; //string to display CO2 value String UVStr; //string to display UV value float AlcR; //floating point value for alcohol float COR; //floating point value for CO float AQR; //floating point value for air quality float CO2R; //floating point value for CO2 float UVR; //floating point value for UV float AlcS; //floating point value for saved alcohol float COS; //floating point value for saved CO float AQS; //floating point value for saved air quality float CO2S; //floating point value for saved CO2 float UVS; //floating point value for saved UV int SCTR = 0; //seconds counter int PCTR = 0; //publish counter int PubFlag = 0; const int buttonPin = PUSH2; // the number of the pushbutton pin int buttonState = 0; // variable for reading the pushbutton status int WiFiFlag = 1; //flag to enable WiFi char mqttAddr[SERVERURLLEN]; int mqttPort = 1883; MACAddress mac; WifiIPStack ipstack; MQTT::Client<WifiIPStack, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack); void setup() { uint8_t macOctets[6]; // setup LCD to display sensor data pinMode(AlcHpin, OUTPUT); //heater control pin pinMode(COHpin, OUTPUT); //heater control pin pinMode(AQHpin, OUTPUT); //heater control pin // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT_PULLUP); // setup LCD to display sensor data myScreen.begin(); myScreen.clearBuffer(); myScreen.setFont(0); Serial.begin(115200); // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); //if the pushbutton is pressed on startup disable WiFi if (buttonState == LOW) { WiFiFlag = 0; } if (WiFiFlag){ // attempt to connect to Wifi network: myScreen.text(5, 1, "Connecting..."); myScreen.flush(); // Connect to WPA/WPA2 network. Change this line if using open or WEP network: WiFi.begin(ssid, password); while ( WiFi.status() != WL_CONNECTED) { // flash + while we wait to connect myScreen.text(86, 1, "+"); myScreen.flush(); delay(200); myScreen.text(86, 1, " "); myScreen.flush(); delay(100); } myScreen.text(5, 1, "WiFi Connected "); myScreen.text(5, 16, "Waiting for ip"); myScreen.flush(); while (WiFi.localIP() == INADDR_NONE) { // wait for an ip addresss delay(300); } // We are connected and have an IP address. myScreen.text(5, 1, "IP obtained"); myScreen.text(5, 16, WiFi.localIP()); mac = WiFi.macAddress(macOctets); // Use MAC Address as deviceId sprintf(deviceId, "%02x%02x%02x%02x%02x%02x", macOctets[0], macOctets[1], macOctets[2], macOctets[3], macOctets[4], macOctets[5]); sprintf(clientId, "d:%s:%s:%s", organization, typeId, deviceId); sprintf(mqttAddr, IOTFSERVER); } delay(400); //to allow the text to be read before erasing myScreen.clear(); myScreen.text(5, 1, "STARTING DAS"); myScreen.flush(); delay(300); //to allow the text to be read before erasing myScreen.clear(); myScreen.clearBuffer(); //display sensor labels myScreen.setFont(1); myScreen.text(5, 1, "SENSORS"); myScreen.setFont(0); myScreen.text(5, 22, "Alc"); myScreen.text(5, 37, "CO"); myScreen.text(5, 52, "AQ"); myScreen.text(5, 67, "CO2"); myScreen.text(5, 82, "UV"); myScreen.flush(); } void loop() { int rc = -1; if (SCTR >= 0 && SCTR < 60) //turn on alcohol heater for 60 seconds digitalWrite(AlcHpin, 1); //turn on heater digitalWrite(COHpin, 0); //turn off heater digitalWrite(AQHpin, 0); //turn off heater if (SCTR > 58 && SCTR < 120) //turn on CO heater for 60 seconds { digitalWrite(AlcHpin, 0); //turn off heater digitalWrite(COHpin, 1); //turn on heater digitalWrite(AQHpin, 0); //turn off heater } if (SCTR > 118 && SCTR < 180) //turn on AQ heater for 60 seconds { digitalWrite(AlcHpin, 0); //turn off heater digitalWrite(COHpin, 0); //turn off heater digitalWrite(AQHpin, 1); //turn on heater } SCTR++; //increment seconds counter PCTR++; //increment publish counter if (SCTR > 179) //reset seconds counter { SCTR = 0; } if (PCTR > 6) //reset publish counter { PCTR = 0; } //Read Sensors AlcValue = analogRead(AlcPin); //read Alcohol sensor COValue = analogRead(COPin); //read CO sensor AQValue = analogRead(AQPin); //read Air Quality sensor CO2Value = analogRead(CO2Pin); //read CO2 sensor UVValue = analogRead(UVPin); //read UV sensor AlcR = (float)AlcValue; COR = (float)COValue; AQR = (float)AQValue; CO2R = (float)CO2Value; UVR = (float)UVValue; if (SCTR == 178) //save good alcohol reading { AlcS = AlcR; } if (SCTR == 118) //save good CO reading { COS = COR; } if (SCTR == 58) //save good AQ reading { AQS = AQR; } AlcStr = String(AlcValue); //convert reading to ASCII for display COStr = String(COValue); //convert reading to ASCII AQStr = String(AQValue); //convert reading to ASCII CO2Str = String(CO2Value); //convert reading to ASCII UVStr = String(UVValue); //convert reading to ASCII myScreen.setFont(0); myScreen.text(40, 22, AlcStr + " "); //display alcohol myScreen.text(40, 37, COStr + " "); //display CO myScreen.text(40, 52, AQStr + " "); //display Air Quality myScreen.text(40, 67, CO2Str + " "); //display CO2 myScreen.text(40, 82, UVStr + " "); //display UV myScreen.text(70, 22, "ppm"); //display units myScreen.text(70, 37, "ppm"); //display units myScreen.text(70, 52, "ppm"); //display units myScreen.text(70, 67, "ppm"); //display units myScreen.text(70, 82, "idx"); //display units myScreen.flush(); delay (1000); if (WiFiFlag) { if (PCTR == 5) //publish on the 5th second of every 6 seconds { if (!client.isConnected()) { // if (WiFi.status() == WL_CONNECTED) { while (rc != 0) { rc = ipstack.connect(mqttAddr, mqttPort); } MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer; connectData.MQTTVersion = 3; connectData.clientID.cstring = clientId; rc = -1; while ((rc = client.connect(connectData)) != 0) ; } //make up messages to publish data and send char ALCjson[12] = "Alc: "; dtostrf(AlcS,1,2, &ALCjson[5]); // ALCjson[1] = '{'; ALCjson[10] = '}'; ALCjson[11] = '\0'; MQTT::Message message; message.qos = MQTT::QOS0; message.retained = false; message.payload = ALCjson; message.payloadlen = strlen(ALCjson); rc = client.publish(pubtopic, message); if (rc != 0) { // error code processing } char COjson[12] = "CO : "; dtostrf(COS,1,2, &COjson[5]); // COjson[1] = '{'; COjson[10] = '}'; COjson[11] = '\0'; message.payload = COjson; message.payloadlen = strlen(COjson); rc = client.publish(pubtopic, message); if (rc != 0) { // error code processing } char AQjson[12] = "AQ: "; dtostrf(AQS,1,2, &AQjson[5]); // AQjson[1] = '{'; AQjson[10] = '}'; AQjson[11] = '\0'; message.payload = AQjson; message.payloadlen = strlen(AQjson); rc = client.publish(pubtopic, message); if (rc != 0) { // error code processing } char CO2json[12] = "CO2: "; dtostrf(CO2R,1,2, &CO2json[5]); // CO2json[1] = '{'; CO2json[10] = '}'; CO2json[11] = '\0'; message.payload = CO2json; message.payloadlen = strlen(CO2json); rc = client.publish(pubtopic, message); if (rc != 0) { // error code processing } char UVjson[12] = "UV: "; dtostrf(UVR,1,2, &UVjson[5]); // UVjson[1] = '{'; UVjson[10] = '}'; UVjson[11] = '\0'; message.payload = UVjson; message.payloadlen = strlen(UVjson); rc = client.publish(pubtopic, message); if (rc != 0) { // error code processing } } } }
IHEF MQTT Subscriber Firmware
/* Invisible Hazardous Environmental Factors by Doug Wong 2017-04-08 Remote Display via MQTT - connects to an MQTT server - subscribes to the topic "IHEF" - displays Alcohol, CO, Air Quality, CO2, UV */ #include <SPI.h> #include <WiFi.h> #include <PubSubClient.h> #include <LCD_SharpBoosterPack_SPI.h> // your network name also called SSID char ssid[] = "aaaaaa"; //network name – change to your system *** // your network password char password[] = "aaaaaa"; //network password – change to your system*** // MQTTServer to use char server[] = "xxx.xxx.x.xx"; //server URL – change to your system*** // String dstring; String astring; char dchar[22]; LCD_SharpBoosterPack_SPI myScreen; //callback section retrieves subscribed data and displays it void callback(char* topic, byte* payload, unsigned int length) { char *cstring = (char *) payload; char *dstring = (char *) payload; for (int i=0; i<=10; i++) { dstring[i] = cstring[i]; } if (cstring[1] == 108) // ALC { myScreen.text(5, 17, dstring); myScreen.text(65, 17, " ppm "); } if (cstring[2] == 32) // CO { myScreen.text(5, 32, dstring); myScreen.text(65, 32, " ppm "); } if (cstring[1] == 81) // AQ { myScreen.text(5, 47, dstring); myScreen.text(65, 47, " ppm "); } if (cstring[2] == 50) // CO2 { myScreen.text(5, 62, dstring); myScreen.text(65, 62, " ppm "); } if (cstring[0] == 85) // UV { myScreen.text(5, 77, dstring); myScreen.text(65, 77, " idx "); } myScreen.flush(); } WiFiClient wifiClient; PubSubClient client(server, 1883, callback, wifiClient); void setup() { //initiallization section connects to MQTT broker Serial.begin(115200); // attempt to connect to Wifi network: myScreen.begin(); myScreen.clearBuffer(); myScreen.setFont(0); myScreen.text(5, 1, "Connecting..."); myScreen.flush(); // Start Ethernet with the build in MAC Address // attempt to connect to Wifi network: // Connect to WPA/WPA2 network WiFi.begin(ssid, password); while ( WiFi.status() != WL_CONNECTED) { // print dots while we wait to connect delay(300); } myScreen.text(5, 9, "WiFi Connected "); myScreen.text(5, 18, "Waiting for ip"); myScreen.flush(); while (WiFi.localIP() == INADDR_NONE) { delay(300); } myScreen.text(5, 27, "IP obtained"); myScreen.text(5, 36, WiFi.localIP()); myScreen.flush(); delay(300); } void loop() { // Reconnect if the connection was lost if (!client.connected()) { if(!client.connect("IHEF")) { } else { if(client.subscribe("IHEF")) { myScreen.text(5, 45, "Subcribed"); myScreen.text(5, 54, "IHEF"); myScreen.flush(); delay(1200); myScreen.clear(); myScreen.text(20, 3, "MQTT IHEF"); myScreen.flush(); } } } // Check if any message were received // on the topic we subscribed to client.poll(); delay(1000); }
It has been fun and informative reading other entries in this challenge, and interacting with participants, I hope everyone enjoyed it as much as I did.
Links to all blogs and videos that document this project are listed here:
Safe and Sound - Invisible Hazardous Environmental Factors Monitoring System - blog 1 of 22 - blog 1
Safe and Sound - Hazardous Factors System - Development Plan - blog 2
Safe and Sound - Hazardous Factor - UV Light - blog 3
Safe and Sound - Hazardous Factor - Air Quality - blog 4
Safe and Sound - Hazardous Gasses PCB - blog 5
Safe and Sound - Hazardous Factor - Radon - blog 6
Safe and Sound - Invisible Hazards System - Kit Unboxing - blog 7
Safe and Sound - MSP-EXP432P401 & Sharp LCD - blog 8
Safe and Sound - Hazardous Factors MQTT Broker - blog 9
Safe and Sound - Hazardous Factors Sensor PCB - blog 10
Safe and Sound - Hazardous Environmental Factors - ELF - blog 11
Safe and Sound - Hazardous Factors MQTT Subscriber & Publisher - blog 12
Safe and Sound - Hazardous Factors System - ARM Car - blog 13
Safe and Sound - Environmental Factors - Wearables - blog 14
Safe and Sound - Environmental Factors - Microwaves - blog 15
Safe and Sound - Environmental Factors - GAS Sensors - blog 16
Safe and Sound - Hazardous Factors Monitoring System - Gas Sensors Module - blog 17
Safe and Sound - Invisible Hazardous Environmental Factors Monitoring System - blog 18
Safe and Sound - Cell Phone Shield Test - blog 19
Safe and Sound - Invisible Hazards Project Spin-offs - blog 20
Safe and Sound - Gas Sensor Demo - blog 21
Safe and Sound - Ultraviolet Light Tests - blog 22
Safe and Sound - Invisible Hazardous Environmental Factors Monitoring System Conclusions - blog 23
MSP-EXP432P401R Publishing Sensor Data to an MQTT Broker
Safe and Sound Hazardous Factors Sensor PCB
Wearable Environmental Factors Instruments
Invisible Hazardous Environmental Factors System
Top Comments