Link to previous posts
- [Dynamic Living-room Lights] Description
- [Dynamic Living-room Lights] Simple System Design
- [Dynamic Living-Room Lights] The YUN review - When the Penguin Met The Arduino.
- [Dynamic Living-Room Lights] The Infineon RGB LED Shield Review
- [Dynamic Living-Room Lights] The Infineon RGB LED Shield -Library!
- [Dynamic Living-Room Lights] The Lights Teaser Video
- [Dynamic Living-room Lights] The YUN talks to OpenHAB
- [Dynamic Living-room Lights] Building the Mood Lights
- [Dynamic Living Room Lights] The XMAS Tree
- [Dynamic Living-Room Lights] IoT Holiday Lights Minions
- [Dynamic Living-Room Lights] The Big Picture - The Final Build
- [Dynamic Living-Room Lights] Paho For Python - Writing better code
Preface
My project for the Internet of Holoday lights was based around our living room which was not very livable. It was a mess and with the upcoming holidays I wanted to set the living room in such a way that it would be suitable for entertaining guests. Additionally I wanted to accomplish the above mentioned in such a way that the holiday lighting becomes part of the living room and I don't need to remove it after the holidays. Hence the concept of Dynamic Living-room Lighting.
In the previous posts, I have review the YUN and the infineon shield and have presented an overview of the project system. I also setup the place for the lighting with some homemade arts and crafts and give a preview of the system setup. I explained the Library I made for the Infineon Shield as well as the implementation for the MoodLights and made them Dynamic. I also made a XMAS Tree with LEDs and some stuff. I connected them to the YUN and made the control for the Xmas Tree Dynamic and static. It is now integrated into the OpenHAB interface and the YUN works as a relay. I have made the minions dance using a DIY approach and connected them to an RPi. I also wrote a python script to get mentions on twitter and play music while controlling the minions. I also showed you the final build but not yet a video. post, I go back to the minions and make them learn MQTT.
In this post while I wait for my video to upload, I explain the code for the tree
The problem
The basic issue that I was facing is the ability to connect two pieces of my project which is the YUN and the Tree together. I initially though of using a wireless route but in the end, since I needed to send a direct audio line to the tree anyways, hence I chose to use the wired approach and an old school way of doing things on it. There are a couple of methods of doing what I am doing like libraries and stuff and any suggestions are welcome.
The Approach
My approach was to build in two steps.
Step 1. Build the communication
Step 2. Build the activity functions around the communication.
I will briefly explain the code for both in the next few sections.
The communications code
I built the communications part on top of the serial interface of the arduino. I generally use the interrupts system in any microcontroller since it makes sure I 'don't wanna miss a thinngg'(-Aerosmith). Sorry about that pun.
Anyways I start with the example code on the arduino and I use the Serial Event example
String inputString = ""; // a string to hold incoming data boolean stringComplete = false; // whether the string is complete
void setup() { // initialize serial: Serial.begin(9600); // reserve 200 bytes for the inputString: inputString.reserve(200); } void loop() { // print the string when a newline arrives: if (stringComplete) { Serial.println(inputString); // clear the string: inputString = ""; stringComplete = false; } } /* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available. */ void serialEvent() { while (Serial.available()) { // get the new byte: char inChar = (char)Serial.read(); // add it to the inputString: inputString += inChar; // if the incoming character is a newline, set a flag // so the main loop can do something about it: if (inChar == '\n') { stringComplete = true; } } }
Here you can see that there is a function called serialEvent() which executes automatically every time the arduino receives a character. There are two global variables that can be accessed from anywhere in the arduino program where we save the received string and a notification flag that a string was completely received. BUT I don't need that so I start by deleting way the code in the functions and write my own.
The serialEvent is supposed to be triggered everytime I get a single byte over the UART and hence the code becomes something like...
void serialEvent() { while (Serial.available()) { // Read a char char inChar = (char)Serial.read(); if(inChar==':'){ // Start New Frame memset(ptr, 0, FRAMESIZE); inFrame=true; myIndex=0; } if(inFrame==true && myIndex<FRAMESIZE){ // Add a byte *(ptr+myIndex)=inChar; myIndex++; } if(myIndex==FRAMESIZE){ inFrame=false; if(inChar=='#') memcpy(&myFrame, ptr, FRAMESIZE); } } }
In my code, I have a global flag inFrame which tells me if I am in between frame receives. The reason why I have it as a global and not a static is because I later want to implement a timer and a time out which means that if it takes too long to receive a complete frame then prolly something is wrong and I need to discard the data because something went wrong.
In this code I simply wait for ':' which is my start of frame and then use memset to initialize the space with 0s and set some flags. In the next iteration, the function will be 'inFrame' and hence it will copy the data to the memory. I understand pointers so I just use that instead of the dozen other methods. I also check for my maxFrameSize since my protocol has a fixed frame size. I can use a variable frame size too but maybe some other day.
In the end if the received data matches the frame size, we check for the endofframe which is a '#'. Everything in between can be a ascii character or anthing else but our code does not care about that. The question is what is that pointer pointing to?
The protocol
I made a structure for my protocol and it's quite simple.
struct sFrame{ char cStart; // Expect : char cMode; // A-Audio, M-Manual with RGB, P-Pattern char cRed; char cGreen; char cBlue; char cEnd; };
As you can see that there are char type variables for everything. These can be replaced but again not our motive right now. In the global space, I do the following.
struct sFrame myFrame, buffer; // Object to store the frame char *ptr = (char*)&buffer; // Point to the object
This creates an object without using the heap (malloc) since I will need a fixed size throughout the lifetime of my system. Next I create a pointer to this buffer BUT cast it into a char type. This makes sure when I ptr++, I jump to the next char in my structure. Easy! But how do I use this?
The Loop
The code for the loop is given below.
void loop() { // print the string when a newline arrives: if(myFrame.cMode=='A'){ //Serial.println("Audio Mode"); hue0 = constrain(map(analogRead(channel), 0, 400, 0, 255), 0, 255); // Read Audio uint32_t color0 = Wheel(hue0); //Shift the current values. for (i = 0; i<NUMPIXELS; i++){ data_array[i+1] = data_array[i]; } data_array[0] = color0; for(i=0; i<NUMPIXELS; i++){ pixels.setPixelColor(i, data_array[i]); pixels.show(); // This sends the updated pixel color to the hardware. } }else if(myFrame.cMode=='M'){ // Manual mode for(i=0; i<NUMPIXELS; i++){ pixels.setPixelColor(i, pixels.Color(myFrame.cGreen, myFrame.cRed, myFrame.cBlue)); pixels.show(); // This sends the updated pixel color to the hardware. } }else if(myFrame.cMode=='P' && myFrame.cRed==0x00){ rainbowCycle(20); }else if(myFrame.cMode=='P' && myFrame.cRed==0x01){ colorWipe(pixels.Color(240, 0, 0), 200); // Red colorWipe(pixels.Color(0, 240, 0), 200); // Green colorWipe(pixels.Color(0, 0, 240), 200); // Blue colorWipe(pixels.Color(240, 240, 0), 200); // Red colorWipe(pixels.Color(0, 240, 240), 200); // Green colorWipe(pixels.Color(240, 0, 240), 200); // Blue } }
In this example, I use the functions from Adafruit's NeoPixel Library to implement the patterns. When in the loop, I check for the mode settings. If its A then so something and if M then do something and if P then do something else. The serial interrupt takes care of serial communication in the background. Since I have created simple objects for the structure hence I can access the member functions with the . operator. Nothing to it.
Conclusion
I wanted to write a short article to explain the working of asynchronous events on a microcontroller and here it is. This is the simplest possible implementation and you can expand it as you like. There is no library code size since there is no library and I hope you got something while reading this. Any suggestions are most welcome and I if you do a project and use any snippet, just say Hi in the comments.
Thanks,
IP