XMAS is over
On January 6, we remove our Christmas tree and lights in Belgium. So it's also time for my Christmas Wreath of Things to switch off.
But we still have our Secret IoT Service going on - and I want to enjoy that for a little longer.
So I switched over to a low profile design: an LCD that glows when one of my Secret IoT Service partners is alive,
and shows the name of the last person that sent me an I'm alive message.
In the picture below, it was peteroakes.
What's happening?
If no one but me is on-line, the display is blank, and the backlight off.
Once I receive a message from one of my friends, the Thing wakes up:
It sets a seconds counter to 120 seconds, and remembers the name of the sender.
The display lights up, and shows who was broadcasting:
Left upper corner shows my countdown timer. Each second the timer decreases.
Right lower corner shows the sender (in this case fvan).
If I receive no new message within 120 seconds, the backlight switches off, the display is blanked
and we go back to sleep.
Code:
// needed for MQTT and Process lib #include <Bridge.h> // MQTT includes start #include <SPI.h> #include <YunClient.h> #include <IPStack.h> #include <Countdown.h> #include <MQTTClient.h> #include <string.h> // MQTT includes end // include the library code: #include <LiquidCrystal.h> #define PIN_LCDLIGHT 10 // start MQTT declarations char printbuf[100]; YunClient c; // replace by a YunClient if running on a Yun IPStack ipstack(c); MQTT::Client<IPStack, Countdown> client = MQTT::Client<IPStack, Countdown>(ipstack); char payLoadBuf[] = {'j', 'a', 'n', 'c', 'u', 'm', 'p', 's', 0}; const char* send_topic = "element14_IoT"; const char* subscribe_topic = "element14_IoT"; const char* _id = "1cfee8dd0afc_yun"; // end MQTT declarations // start frederick declarations unsigned int uFrederickIsAlive = 0; // end frederick declarations // initialize the library with the numbers of the interface pins // LiquidCrystal lcd(12, 11, 5, 4, 3, 2); LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7); char lastPayload[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // start timer functionality ============================================================ boolean bRunSeconds = false; boolean bIsRunningSeconds = false; boolean bRunMinutes = false; boolean bIsRunningMinutes = false; boolean bRunHours = false; boolean bIsRunningHours = false; void runSeconds() { bIsRunningSeconds = true; // // Serial.print("s"); // remove when confident // task: keep MQTT alive client.yield(30); // this takes 30 ms. May reduce the parameter // if you get duplicates, increase // task: handle frederick alive functionality // task: every minute; we take one live away from frederick if (uFrederickIsAlive) { uFrederickIsAlive--; sprintf(printbuf, "%3u%c", uFrederickIsAlive, 0); lcd.setCursor(0, 0); lcd.print(printbuf); lcd.setCursor(0, 1); lcd.print(lastPayload); pinMode(PIN_LCDLIGHT, INPUT); // high impedance turns on light } else { pinMode(PIN_LCDLIGHT, OUTPUT); // low impedance LOW turns off light sprintf(printbuf, " %c", 0); lcd.setCursor(0, 0); lcd.print(printbuf); lcd.setCursor(0, 1); lcd.print(printbuf); } Serial.println(uFrederickIsAlive); bRunSeconds = false; bIsRunningSeconds = false; } void runMinutes() { bIsRunningMinutes = true; // // Serial.println("m"); // remove when confident // task: flag to Frederick that I'm alive sendAliveMessage(); bRunMinutes = false; bIsRunningMinutes = false; } void runHours() { bIsRunningHours = true; // // Serial.println("h"); // remove when confident bRunHours = false; bIsRunningHours = false; } void timerInit() { // initialize timer1 for 1 second ticks; ISR(TIMER1_COMPA_vect) will be called as interrupt handler noInterrupts(); // disable all interrupts TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 62500; // compare match register 16MHz/256/1Hz TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= (1 << CS12); // 256 prescaler TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt interrupts(); // enable all interrupts } ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine { static unsigned int uSeconds = 0; uSeconds++; // every call is a second bRunSeconds = true; // so yes, flag that the seconds handler should be called bRunMinutes = ! (uSeconds % 60); // each 60th second, flag that the minutes handler should be called if (uSeconds > 3599) { // every hour bRunHours = true; // flag that the hours handler should be called uSeconds = 0; // and start over } } void timerTasks() { if (bRunSeconds && ! bIsRunningSeconds) { // timer interrupt flagged that seconds handler should be called runSeconds(); // but we only run it if it's not active } if (bRunMinutes && ! bIsRunningMinutes) { // timer interrupt flagged that minutes handler should be called runMinutes(); // but we only run it if it's not active } if (bRunHours && ! bIsRunningHours) { // timer interrupt flagged that hours handler should be called runHours(); // but we only run it if it's not active } } // end timer functionality ===================================== // start MQTT functionality ==================================== void mqttInit() { // Ethernet.begin(mac); // replace by Bridge.begin() if running on a Yun Bridge.begin(); // // Serial.println("MQTT Internet of Holiday Lights example"); connect(); } void messageArrived(MQTT::MessageData& md) // this handler is called when a subscribed MQTT message arrives { MQTT::Message &message = md.message; // debug code sprintf(printbuf, "Message arrived: qos %d, retained %d, dup %d, packetid %d\n", message.qos, message.retained, message.dup, message.id); Serial.print(printbuf); sprintf(printbuf, "Payload %s\n", (char*)message.payload); Serial.print(printbuf); /* // sprintf(printbuf, "Topic len %d\n", md.topicName.lenstring); int i; for (i = 0; i < (md.topicName.lenstring.len); i++) { printbuf[i] = md.topicName.lenstring.data[i]; } printbuf[(md.topicName.lenstring.len)]= '\n'; printbuf[md.topicName.lenstring.len + 1]= 0; */ int iPlCheck = strncmp(payLoadBuf, (char*)message.payload,8); if (iPlCheck) { Serial.print(printbuf); sprintf(lastPayload, "%16s", (char*)message.payload); uFrederickIsAlive = 120; // we give frederick two lives (minutes) to send an 'I am alive' live message. } else { Serial.println("it's my own message"); } } void connect() // connect to the MQTT broker { char hostname[] = "iot.eclipse.org"; int port = 1883; sprintf(printbuf, "Connecting to %s:%d\n", hostname, port); // // Serial.print(printbuf); int rc = ipstack.connect(hostname, port); if (rc != 1) { sprintf(printbuf, "rc from TCP connect is %d\n", rc); // // Serial.print(printbuf); } // // Serial.println("MQTT connecting"); MQTTPacket_connectData data = MQTTPacket_connectData_initializer; data.MQTTVersion = 3; data.clientID.cstring = (char*)_id; rc = client.connect(data); if (rc != 0) { sprintf(printbuf, "rc from MQTT connect is %d\n", rc); // // Serial.print(printbuf); } // // Serial.println("MQTT connected"); rc = client.subscribe(subscribe_topic, MQTT::QOS1, messageArrived); if (rc != 0) { sprintf(printbuf, "rc from MQTT subscribe is %d\n", rc); // // Serial.print(printbuf); } // // Serial.println("MQTT subscribed"); } void sendAliveMessage() { if (!client.isConnected()) connect(); MQTT::Message message; char buf[100]; int rc; // Send QoS 1 message // // Serial.println(payLoadBuf); message.qos = MQTT::QOS1; message.retained = false; message.dup = false; message.payload = (void*)payLoadBuf; message.payloadlen = strlen(payLoadBuf)+1; rc = client.publish(send_topic, message); } // end MQTT functionality ============================== // start LCD functionality =========================== void setupLCD() { pinMode(PIN_LCDLIGHT, OUTPUT); //Set control pins to be outputs digitalWrite(PIN_LCDLIGHT, LOW); lcd.begin(16, 2); // lcd.setCursor(0, 0); } // end LCD functionality =========================== void setup() { Serial.begin(9600); delay(10000); // give me time to start the yun monitor // MQTT related tasks mqttInit(); // initialise LCD setupLCD(); // timer related tasks timerInit(); } void loop() { timerTasks(); // non timer related functionality comes here }