Skip navigation
1 2 Previous Next

Arduino

26 Posts authored by: peteroakes Top Member

You know your an Engineer when this combination of ICONS means something exciting

texas instruments.jpgArduino_logo_pantone.pngelement14logo_highres.jpeg

So a few of you may already have seen the video and post regarding using the DAC8734 from TI with the Raspberry PI so you will know what this is all about, for those that have not, you can see it here: Raspberry PI 2.0, Windows 10 and how to drive the DAC8734 from TI (AKA the DAC8734EVM Road test Board)

For those whome have not and or are interested in Interfacing the Arduino to this wonderful chip, lets begin

 

OK, so it’s been a busy week learning, researching and creating sample content for the Arduino, Launchpads and Raspberry PI, to drive the DAC8734 Quad 16bit DAc from Texas Instruments. you can find the others in seperate posts in this community

 

I have been learning about this chip for a few weeks and when I realized it was going to be part of a Road test I decided to clean up some of my test code and make a blog out of it to help others and in particular the road testers. this task was made more difficult because of the seeming lack of information outside of the actual datasheet for the chip which can be found here; http://www.ti.com/lit/ds/symlink/dac8734.pdf

 

I also want to be clear The Road test is about the   I don’t have the  DAC8734EVMDAC8734EVM to hand but I do have a DAC8734 Chip and mounted one on a breakout board and created my circuit on a breadboard but there is nothing I am aware of that will prevent any of my software attached from working on the EVM without change

Here is my breadboard version and a view of some of the other end of the wires going to the Arduino UNO

P1010826.JPGP1010802.JPGP1010837.JPG

This is the EVM module from the Road test, even though the chip is on an evaluation PCB with two VREFS and a bunch of switches, there should be no difference in operation of the software

DAC8734EVM.jpg,

if your wiring to this then you will need to connect the SPI lines and power to the J2A pins (Right hand side of the EVM)

If you jumper J2.2 to J2.8 and J2.6 to J2.12 then after the SPI and power is connected, the board will work with my software in the same way.

 

The DAC8734 stands out from many other DACs in that is can output upto +20V in unipolar mode and +10 to - 10 in Bipolar mode, this coupled with the 16Bit resolution and less than 1 bit error after calibration makes this DAC an Ideal candidate for my Power Supply project,

Here is a complete list of its features

DAC8734 Features.png

 

The dac consists of 4 analog outputs, a couple of GPIO pins, VREF inputs and the usual set of communications and power pins, here is a block diagram and a mode detailed drawing of one channel

DAC8734 BLOCK DIAGRAM.pngDAC8734 1 Chan DIAGRAM.png

One really cool thing to note here that is also fairly unique among DACs is the Zero and Gain registers, these allow the engineer to actually tune the zero offset of each individual DAC channel and also change its gain. this permits the engineer to not have to worry about software calibration that involves adjusting the actual Binary value being output to the DAC data registers, instead they can leverage the complete range of values (65535) for the best resolution. By making the jumper connections I listed above allows the engineer to also control the mode of operation for group A and B between Bipolar and Unipolar operation, rather then using the onboard switches or hard wiring it

 

To say there were not any issues that I still have not resolved would be wrong. This is not a critical issue but on the PI and according to the DAC8734 PDF, the chip is supposed to work in SPI Clocking MODE1 where the data is changed on the rising edge of the clock and then latched into the DAC on the falling edge and this works perfectly on the PI (Once I figured that out )

 

when I initially coded the cleaned up Arduino sketch, I set it to the same mode and it did not work. It was working before i tried to set any mode and simply accept the default, and I wrongly assumed that it was operating in Mode 1... wrong

Here is the timeing diagram from the PDF

DAC8734 Timing.png

the trace from the working RPI code

DAC1 AAAA mode 1.png

and this is what I had to use to get the Arduino working... just weird as the PDF has no mention of being able to reliably work this way... im still investigating

tek00001.pngtek00002.png

If anyone has any ideas, please let me know and I will try it out, for now be aware that you may also need to operate the DAC in this mode, even though it seems to be wrong (Yes I did adjust the Oscilloscope triggering correctly.. I thought of that )

 

For accuracy I was impressed but I have no means currently to measure the full accuracy of this DAC but I have my name in the hat too for the road test so we will see. For now I will simply say that i was able to tune it to within 2 digits on my 4.5Digit DMMs but the DAC is way better than that so I wont show measurements here as they will serve no point. I do have operational test measurements shown in the PI video and I will be creating a video for this DAC too, its just not ready yet

 

So lets look at the software. First let me say, I have tried to make it compatable with both the Arduino and the Launchpads and so far I have succeeded. there is an assumption that in all cases, where a board has a SS (Slave Select) defined, I have used it. this is all of the boards tested so far including the Arduino so here is the pinout I used for the Arduino

ArduinoUno_R3_Front.jpgbasically 10 is Chip select, 11 is MOSI (Master Out, Slave In), 12 is MISO (Master In, Slave Out) and 13 is the clock. this is all in hardware on the Arduino UNO with the exception of the SS pin that you still need to cotrol seperatly

 

 

OK, the code will be attached to this post as a complete sketch but below I will break it down as I go through its operation

 

The first section upto the area identified as // DAC8734 code starts here is standard stuff to do with reading the serial port, parsing the commands and a few buffers, all previously described in my earlier videos and posts

 

the part following is where we start into the DAC code

 

 

//********************************************************
// DAC8734 code starts here
//********************************************************


// PICK THE RIGHT chip select for the right board


#define DAC_8734_CS_PIN  SS  // All the boards tested so far has this pin defined and it is in a consistent place on the expansion headers


#define VREF 5.000
// Default values below assume 0-10V Unipolar or -5 to +5 bipolar output
#define DAC_VFSR VREF*2 // may be 0 - 10 or -5 to +5
#define DAC_8734_Command 0 // command register
#define DAC_8734_DataBase 0x04 // register offset to zero cal base register
#define DAC_8734_CalZeroBase 0x08 // register offset to zero cal base register
#define DAC_8734_CalGainBase 0x0C // register offset to gain cal base register
#define DACMAX 0xFFFF
#define DACMIN 0x0000


// default setup of DAC8734, these can be adjusted if needed, some functions also change them to change mode etc.
int DAC_Gain0 = 0; // 0 = *2, 1 = *4
int DAC_Gain1 = 0; // 0 = *2, 1 = *4
int DAC_Gain2 = 0; // 0 = *2, 1 = *4
int DAC_Gain3 = 0; // 0 = *2, 1 = *4
int DAC_GPIO0 = 1; // 1 = Group A in Unipolar 0=Bipolar (External connection to control pin)
int DAC_GPIO1 = 1; // 1 = Group B in Unipolar 0=Bipolar (External connection to control pin)
int DAC_PD_A = 0;  // 1 = group A power down
int DAC_PD_B = 0;  // 1 = group B power down
int DAC_DSDO = 0;  // 1 = Disable SDO bit.


// set up the speed, data order and data mode
// See https://www.arduino.cc/en/Reference/SPI for more details


#ifdef Arduino
// not available on energia yet
SPISettings settingsDAC8734(5000000, MSBFIRST, SPI_MODE0);
#endif


// Sine table, used to create a reasonable sinewave on a dac output, 256 16bit values, one complete cycle
byte val = 0;
unsigned int Sin_tab[256] = {  32768, 33572, 34376, 35178, 35980, 36779, 37576, 38370, 39161, 39947, 40730, 41507, 42280,
                               43046, 43807, 44561, 45307, 46047, 46778, 47500, 48214, 48919, 49614, 50298, 50972, 51636,
                               52287, 52927, 53555, 54171, 54773, 55362, 55938, 56499, 57047, 57579, 58097, 58600, 59087,
                               59558, 60013, 60451, 60873, 61278, 61666, 62036, 62389, 62724, 63041, 63339, 63620, 63881,
                               64124, 64348, 64553, 64739, 64905, 65053, 65180, 65289, 65377, 65446, 65496, 65525, 65535,
                               65525, 65496, 65446, 65377, 65289, 65180, 65053, 64905, 64739, 64553, 64348, 64124, 63881,
                               63620, 63339, 63041, 62724, 62389, 62036, 61666, 61278, 60873, 60451, 60013, 59558, 59087,
                               58600, 58097, 57579, 57047, 56499, 55938, 55362, 54773, 54171, 53555, 52927, 52287, 51636,
                               50972, 50298, 49614, 48919, 48214, 47500, 46778, 46047, 45307, 44561, 43807, 43046, 42280,
                               41507, 40730, 39947, 39161, 38370, 37576, 36779, 35980, 35178, 34376, 33572, 32768, 31964,
                               31160, 30358, 29556, 28757, 27960, 27166, 26375, 25589, 24806, 24029, 23256, 22490, 21729,
                               20975, 20229, 19489, 18758, 18036, 17322, 16617, 15922, 15238, 14564, 13900, 13249, 12609,
                               11981, 11365, 10763, 10174, 9598, 9037, 8489, 7957, 7439, 6936, 6449, 5978, 5523, 5085, 4663,
                               4258, 3870, 3500, 3147, 2812, 2495, 2197, 1916, 1655, 1412, 1188, 983, 797, 631, 483, 356, 247,
                               159, 90, 40, 11, 1, 11, 40, 90, 159, 247, 356, 483, 631, 797, 983, 1188, 1412, 1655, 1916, 2197,
                               2495, 2812, 3147, 3500, 3870, 4258, 4663, 5085, 5523, 5978, 6449, 6936, 7439, 7957, 8489, 9037,
                               9598, 10174, 10763, 11365, 11981, 12609, 13249, 13900, 14564, 15238, 15922, 16617, 17322,
                               18036, 18758, 19489, 20229, 20975, 21729, 22490, 23256, 24029, 24806, 25589, 26375, 27166,
                               27960, 28757, 29556, 30358, 31160, 31964
                            };


//Calibration table, you will need to adjust these values to suit your build
int DAC_CAL_tab[8] = { 0x08, 0xfF, 0x0F, 0x4F,   0x3f, 0x80, 0x80, 0x80}; // zero's then gain's


// The DAC8734 uses Mode 1 SPI, has an 8 bit address byte followed by 16bit data
// high byte first, high bit first
// This is the register descriptions
// Reg   description
// 0    Control Register
// 1    Monitor
// 2    Not Used
// 3    Not Used
// 4    DAC 0 Data Register
// 5    DAC 1 Data Register
// 6    DAC 2 Data Register
// 7    DAC 3 Data Register
// 8    DAC 0 Zero Cal Register
// 9    DAC 1 Zero Cal Register
// a    DAC 2 Zero Cal Register
// b    DAC 3 Zero Cal Register
// c    DAC 0 Zero Gain Register
// d    DAC 1 Zero Gain Register
// e    DAC 2 Zero Gain Register
// f    DAC 3 Zero Gain Register


This section defines loads of constants, register offsets and a SINE table for fun waveform generation, it is all configured in support of the DAC and I will walk through it in more detail in the pending video

All of the code has been heavily commented to make it easier to understand and extend. I have deliberatly NOT made a library yet as I want this to be as simple as possible for the reader to understand

now we start into real code for the DAC

At its core, WriteDACRegister function does everything or more specifically is the only unction that actually initiates communications with the SPI bus and the DAC chip, all the other functions end up here, so if you have issues, this is a good place to put debug statements

// the most basic function, write to register "reg", with a value "val"
void WriteDACRegister(byte reg, unsigned int val)
{ 
#ifdef Arduino 
  SPI.beginTransaction(settingsDAC8734); // ensures the SPI bus is in the right mode for this device irrespective of other devices used in the code
#endif
  digitalWrite(DAC_8734_CS_PIN, LOW); // Select the Chip
  SPI.transfer(reg); // Select the target register
  SPI.transfer(val >> 8); // Send the High Data Byte
  SPI.transfer(val & 0xFF); // Send the Low Data Byte
  digitalWrite(DAC_8734_CS_PIN, HIGH); // Release the Chip
#ifdef Arduino
  SPI.endTransaction();
#endif
}

it is very simple, it takes an 8bit register offset and a 16 bit value and sends it to the DAC via the SPI bus, register value first, followed by high Byte of value, then the low byte. A point to note in this function if the ifdef statements, these are compiler directives that are used if you set the Arduino Definition at the top of the code to active, the Arduino will work fine without it but this allows you to more easily change the speed of the bus and its mode, if for some reason you have more than one device on the bus with different operating modes, to read more, look here: https://www.arduino.cc/en/Reference/SPI

 

Now we have the DAC initialization, this simply takes all the "int" variables at the top of the DAC code, ors them all together shifting the bits as needed to create the command word to setup the DAC.The default I have currently is both Group A and B are powered up and running in Unipolar mode with a 2X gain

// Setup a default DAC using the variables set above
// note the variables can be chaned then recall InitDac to change mode
// of operation of the DAC
// Currently set to Unipolar, 2* Gain and Powered up
void InitDAC()
{
  // for now, gain of 2, gpio hiZ,
  int DAC_INIT = 0x0000 | DAC_PD_A << 12 | DAC_PD_B << 11 | DAC_GPIO1 << 9 | DAC_GPIO0 << 8 | DAC_DSDO << 7 | DAC_Gain3 << 5 | DAC_Gain2 << 4 | DAC_Gain1 << 3 | DAC_Gain0 << 2 ;
  Serial.print("Command Reg = "); Serial.print(DAC_INIT, HEX); Serial.print(" "); Serial.println(DAC_INIT, BIN);
  WriteDACRegister(DAC_8734_Command, DAC_INIT);
}

 

now we have Calibrate DAC, this function simply outputs an 8*16 bit table to the Zero and Gain registers of the DAC. when you try it, you will need to adjust the values of this table to suit your own DAC, have a read of the PDF here fo more details: http://www.ti.com/lit/ds/symlink/dac8734.pdf page 19.

//Output the Calibration table to the DAC for all channels
void CalibrateDAC()
{
  for (int x = 0 ; x < 4 ; x++)
  {
    WriteDACRegister(DAC_8734_CalZeroBase + x, DAC_CAL_tab[x]) ;// Zero cal
    WriteDACRegister(DAC_8734_CalGainBase + x, DAC_CAL_tab[x + 4]); // Gain cal
  }
}

 

Another simple function that abstracts the DAC values from knowing the register offsets etc

// Helper Function to output to a specified DAC, a Desired value between 0 and 65535
// this could represent 0V - 10V or -5 to +5V depending on mode
void SetDAC( byte channel, unsigned int value)
{
  if (channel > 3)
  {
    Serial.println("DAC  must be 0 - 3");
  }
  else
  {
    //Serial.print("DAC "); Serial.print(channel); Serial.print(" Value "); Serial.println(value, HEX);
    WriteDACRegister(DAC_8734_DataBase + channel, value);
  }
}

This simply takes a DAC value between 0 and 3 along with a 16bit value, performs a quick check on the DAC id and adds the DAC base register value to it and forwards it to the WriteDACRegister function

 

Now is a fun function, this itterates through the SineTable above and outputs each value in turn to the DAC, there are 256 values in the table, and the routine will send out each complete set upto the number provided as the value in the call, this can be from 0 to 65535 (A long time if you go there ). the first parameter simply selects the DAC channel you want to output the value to.

// Simple itteration through the sine table above to simulate a sinewave
// you can change the table contents above to send whatever wave shape you want
void sine( byte channel, unsigned int loopcount)
{
  if (loopcount > 65535) loopcount = 65535;
  if (channel > 3) channel = 0;
  Serial.print("Sine on DAC ");Serial.print(channel ); Serial.print(" Cycles= ");Serial.println(loopcount);
  for (int y = 0 ; y < loopcount ; y++)
  {
    for (int x = 0 ; x < 256 ; x++)
    {
      SetDAC(channel, Sin_tab[x]);
    }
  }
  Serial.println("Complete");
}

 

This one should be self explanatory

// Send to Serial port the Help Menu
void help()
{
  // Print some pretty instructions
  Serial.println("DAC8734 Test Program:");
  Serial.println("Peter Oakes, July 2015\n");
  Serial.println("Commands:");
  Serial.println("help\" for this menu" );
  Serial.println("dacx  x is from 0 to 3, value 0 to 65535" );
  Serial.println("bpA or bpB mode  Bipolar");
  Serial.println("upA or upB mode Unipolar" );
  Serial.println("offA or offB Power Off group A or B" );
  Serial.println("onA or onB   Power On for Group A or B" );
  Serial.println("sinex cycles, x is DAC from 0 to 3, cycles 0 to 65535" );
  Serial.println();
  Serial.println("make sure \"NewLine\" is on in the console setup" );


}

 

The setup and loop functions are very basic and self explanatory too

//********************************************************
// Standard Arduino / Energia setup() and loop() functions
// do not delete
//********************************************************
void setup()
{
  Serial.begin(115200);
  // print the help menu for the DAC8734 tester
  help();
  // setup the chip select pin for the DAC
  pinMode(DAC_8734_CS_PIN, OUTPUT);
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  // Initialisze the DAC8734
  InitDAC();
  // output the DAC_CAL_tab to the DAC
  CalibrateDAC();
  // set the DAC outputs to Zero
  SetDAC(0, 0x0000);
  SetDAC(1, 0x0000);
  SetDAC(2, 0x0000);
  SetDAC(3, 0x0000);
}


void loop()
{
  // see if there is a command come in on the serial port and if so call the command processor
    if (CheckSerial()) DoCommand(inputBuffer);
}

 

Well OK, loop is a little strange for some of you. A long time ago i created several tutorials on how to read the serial port and parse the strings into usable commands with a single parameter. the statement in the loop simply chaecks the serial function to see if a command has arrived (Signified by he receipt of a newline character and if one is found, it sends it to the "DoCommand" function where all the magic happens. You can see the POST here if you want more information on how it works etc, Fast Track to Arduino Programming - Lesson 3 pt 1, Improved Parsing and memory usage (Fully working programs) and here Fast Track to Arduino Programming - Lesson 2, parsing the serial input into usable commands

 

here is the code anyway to complete the sketch

//********************************************************
// UTILITY FUNCTIONS TO MAKE LIFE EASY
//********************************************************
/*
Checks the serial input for a string, returns true once a '\n' is seen
users can always look at the global variable "serialIndex" to see if characters have been received already
*/
boolean CheckSerial()
{
  boolean lineFound = false;
  // if there's any serial available, read it:
  while (Serial.available() > 0) {
    //Read a character as it comes in:
    //currently this will throw away anything after the buffer is full or the \n is detected
    char charBuffer = Serial.read();
    if (charBuffer == '\n') {
      inputBuffer[serialIndex] = 0; // terminate the string
      lineFound = (serialIndex > 0); // only good if we sent more than an empty line
      serialIndex = 0; // reset for next line of data
    }
    else if (charBuffer == '\r') {
      // Just ignore the Carrage return, were only interested in new line
    }
    else if (serialIndex < serialbufferSize && lineFound == false) {
      /*Place the character in the string buffer:*/
      inputBuffer[serialIndex++] = charBuffer; // auto increment index
    }
  }// End of While
  return lineFound;
}// End of CheckSerial()




// Enhanced Command Processor using strtok to strip out command from multi parameter string
boolean DoCommand(char * commandBuffer)
{
  Serial.println("Command");
  char* Command; // Command Parameter
  char* Parameter; // Additional Parameter
  unsigned int analogVal = 0; // additional parameter converted to analog if possible


  // Get the command from the input string
  Command = strtok(commandBuffer, commandDelimeters); // get the command
  Parameter = strtok(NULL, commandDelimeters); // get the parameter if any
  //if there are more than one parameter they will be ignored for now


  // Make sure we have an analog value if we are to allow PWM output
  unsigned int outparameter = isNumeric (Parameter);


  //if it is a number then convert it
  if (outparameter)
  {
    analogVal = atoi(Parameter);
    // check the analog value is in the correct range
    if (analogVal < DACMIN || analogVal > DACMAX) outparameter = false;
  }
  // Standard way to handle commands
  if (strcmp(Command, "help") == 0) { help(); }
  //DAC Outputs if we have a valid analog parameter
  else if (strcmp(Command, "dac0") == 0  && outparameter ) { SetDAC(0, analogVal);}   // Set the DAC 0 output 
  else if (strcmp(Command, "dac1") == 0  && outparameter ) { SetDAC(1, analogVal);}  // Set the DAC 1 output 
  else if (strcmp(Command, "dac2") == 0  && outparameter ) { SetDAC(2, analogVal);}   // Set the DAC 2 output 
  else if (strcmp(Command, "dac3") == 0  && outparameter ) { SetDAC(3, analogVal);}   // Set the DAC 3 output 
  //Sine Wave Outputs
  else if (strcmp(Command, "sine0") == 0  && outparameter ) { sine(0,analogVal);}    // Set the DAC 3 output 
  else if (strcmp(Command, "sine1") == 0  && outparameter ) { sine(1,analogVal);}   // Set the DAC 3 output 
  else if (strcmp(Command, "sine2") == 0  && outparameter ) { sine(2,analogVal);}   // Set the DAC 3 output 
  else if (strcmp(Command, "sine3") == 0  && outparameter ) { sine(3,analogVal);}   // Set the DAC 3 output 
  // UNIPOLAR
  else if (strcmp(Command, "upA") == 0 ) { Serial.println("Setting UniPolar  Group A");  DAC_GPIO0 = 1; InitDAC(); }
  else if (strcmp(Command, "upB") == 0 ) { Serial.println("Setting UniPolar  Group B");  DAC_GPIO1 = 1; InitDAC(); }
  // BIPOLAR
  else if (strcmp(Command, "bpA") == 0 ) { Serial.println("Setting BiPolar  Group A");   DAC_GPIO0 = 0; InitDAC();  }
  else if (strcmp(Command, "bpB") == 0 ) { Serial.println("Setting BiPolar  Group B");   DAC_GPIO1 = 0; InitDAC();  }
  // Power Down
  else if (strcmp(Command, "offA") == 0 ) {Serial.println("GrpA Off "); DAC_PD_A = 1; InitDAC(); }
  else if (strcmp(Command, "offB") == 0 ) {Serial.println("GrpB Off "); DAC_PD_B = 1; InitDAC(); }
  // Power Up
  else if (strcmp(Command, "onA") == 0 ) { Serial.println("GrpA On"); DAC_PD_A = 0; InitDAC(); }
  else if (strcmp(Command, "onB") == 0 ) { Serial.println("GrpB On"); DAC_PD_B = 0; InitDAC(); }
  // Catch All
  else {  Serial.print("Error "); Serial.println(commandBuffer); }
  return true;
}
// Utility function to make sure the string is a numneric one
int isNumeric (const char * s)
{
  while (*s)
  {
    if (!isdigit(*s)) return 0;
    s++;
  }
  return 1;
}

 

and basically thats it. If you thought it was going to be tough to use this DAC, I hope now you have other ideas. Feel free to use theis sketch as you please, provide feedback and any bugs you find and perhaps even feture requests ??, who knows what I may choose to do but one thing for sure, this is a nice little DAC with a lot of possibilities and I look forward to using it on future projects.

 

as soonas you load the sketch and attach the console it should print out the help screen telling you the commands available, I hope you find it useful, I will be creating a video to go with this and if I improve the code and add more features I will post that too.

I just got this come through to my email, so I thought I would share it with you all

 

it is short notice, Im going so if your in Ontario and go, ill see you there

 

Regards

 

Peter

 

Atmel Tech on Tour is coming to Ontario in April

http://training.atmel.com/TechOnTour_NorthAmerica

Back to the main blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

 

In the earlier blog about the Infineon I evaluated the demo and created a library to drive the board from that code which worked out quite well, but it was not complete from the IoT of Holiday Lights perspective

 

Radio interface to Mrs YUN was missing along with a few commands already demonstrated in various videos

 

This will provide a quick walk through the current level of the code highlighting a few of the aspects to control the lights attached to the shield

 

infinion LED Controller.pngArduino_Uno_Angle.jpg24L01.jpg

 

first the need to add in all the libraries for the NRF24L01, the Infineon and support libraries

// Bunch of constants in the form of definitions
// 1 = output debug to serial port, 0 = no debug
#define debug 1
/* Include needed Lbraries */
#include <SPI.h>
#include <Wire.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include <Infineon.h>
#include <avr/pgmspace.h>
/* End include libraries */

Infineon RGBLEDS = Infineon();

 

The Infinion.h is the library I created from the original demo, then added a couple extra features like a colour lookup and an ability to directly set the colour by name

 

Here is the enum from Infineon.h

typedef enum  {White, Silver, Gray, Black, Red, Maroon, Yellow, Olive, Lime, Green, Aqua, Teal, Blue, Navy, Fuchsia, Purple} Colours;

 

this allows you to set the colour by a friendly name

 

and in the main Infineon.c file the actual support code for this

void Infineon::SETCOLOUR(uint8_t Colour)
{
  switch(Colour)
  {
  case White: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x800);break;
  case Silver: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xC00, 0xC00, 0xC00);break;
  case  Gray: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x800);break;
  case Black: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0x0);break;
  case Red: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0x0, 0x0);break;
  case Maroon: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x0, 0x0);break;
  case Yellow: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0xFFF, 0x0);break;
  case Olive: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x800, 0x0);break;
  case Lime: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0xFFF, 0x0);break;
  case Green: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x800, 0x0);break;
  case Aqua: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0xFFF, 0xFFF);break;
  case Teal: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x800, 0x800);break;
  case Blue: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0xFFF);break;
  case Navy: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x0, 0x0, 0x800);break;
  case Fuchsia: I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0xFFF, 0x0, 0xFFF);break;
  case Purple:I2CWRITE6BYTES(ADDRESS, INTENSITY_RGB, 0x800, 0x0, 0x800);break;
  default: break;
  }

 

As you can see this is easy to extend and adjust the colours to get them right, currently some are a bit off when using an LED 12V string as the output., this function can probably be optimized if needed but for now it is easy to follow and update

 

Back to the main code, skipping the parts related to the radio as there described in the other blog entries

now we come to the variables and enums related to the mode of operation and timing control

enum modes {cSOLID, cFLASH, cRAINBOW};
modes colourMode = cSOLID ; // mode 0 = static, 1 = flash, 2 = rainbow
boolean isBright = true;
int flashTime = 500; // 500mS
int nextFlash ;

//enumeration to make accessing the command strings easier
enum {hello, SETCOLOUR, RED, GREEN, BLUE, WHITE, FLASH, RAINBOW,
      OFF  };
//Command Strings
PROGMEM const char helloCmd[]     = "Hello";
PROGMEM const char SETCOLOURCmd[]    = "SETCOLOUR";
PROGMEM const char REDCmd[]      = "RED";
PROGMEM const char GREENCmd[]    = "GREEN";
PROGMEM const char BLUECmd[]     = "BLUE";
PROGMEM const char WHITECmd[]    = "WHITE";
PROGMEM const char FLASHCmd[]    = "FLASH";
PROGMEM const char RAINBOWCmd[]  = "RAINBOW";
PROGMEM const char OFFCmd[]   = "OFF";

 

Rainbow has not yet been implemented but Flash has and is described below, the last few parameters re-use some of my tutorial code from this series Fast Track to Arduino Programming, if you want to know the details, please feel free to go look

suffice to say here that it defines the commands that can be received over the serial port of the NRF radio, the SETColourCmd was demonstrated being used from the WEB Page demo utilizing the colour wheel

 

Skipping down to the setup() loop we see a style of mine that I encourage others to follow. That is to modularize our code right from the start, unless your running out of Flash and really need to get that last byte back, there is no reason not to and you will quickly understand the benefits of seperating the various parts of functionality (Easy of maintenance, Understanding, editing and debugging)

 

void setup()
{
  // initialize serial:
  Serial.begin(57600);
  // do other setup here as needed
  initialiseNRF();


  Wire.begin();
  initialiseInfineon();
  nextFlash = millis();
  // initialise all the digital outputs
}

 

As you can see, the work to initialize the Infineon board and the radio have been abstracted into separate functions and now the setup() function is easy to read and understand without having to know what is happening elsewhere

 

the same thing goes for the main loop

void loop()
{
  // Notice how the main loop is very simple and the functions
  // seperate the logic into easily manageable parts
  if (CheckSerial())
  {
    DoCommand(inputBuffer, "\0");
  }

  if (CheckNRF())   
  {
    DoCommand(NRFrdata, "\0");
    SendNRFTest(); // echo back command
  }

  // Do other stuff
  switch (colourMode)
  {
    case  cFLASH: infinionFLASH() ; break;
    case cRAINBOW: infinionRAINBOW() ;break;
  }
}

for all this code does, there is not a lot in the main loop as it is all extracted into small manageable functions

 

the first to calls (Check Serial and Check NRF basically do the same thing but with very different hardware, one checks the serial port for a message and if found it puts the message into a buffer, returns it to here and then it is passed to the DoCommand() function to be processed

the CheckNRF function call does the exact same thing except it checks the NRF Radio for data

 

lastly if a colour mode command has been sent in, the loop will call a function associated with that command. That is all that is required int he main loop to process commands from multiple sources and manage modes etc. yet with all that, just like the setup() method, it is easy to follow and understand without having to know the details of all the functions it uses

 

that brings me to a tip... Please please name functions something meaningful and the same goes for variables, it makes life so much easier when you go back at a later date to change things or if you share the code

 

Now skipping past the code described in my tutorials we come to the first specific function to use the RGB shield

void infinionSetRGB(char* RGBColour)
{
  //char printbuf[32];
  long number = (long) strtol( RGBColour, NULL, 16);
  long r = number >> 16;
  long g = number >> 8 & 0xFF;
  long b = number & 0xFF;
  RGBLEDS.I2CWRITE6BYTES (ADDRESS, INTENSITY_RGB, r << 4, g << 4, b << 4);
  //sprintf(printbuf, "%s - Number: %ld - R: %d, G: %d, B: %d\n", RGBColour, number, r, g, b);
  //Serial.print(printbuf);
}

 

As you can see again, short, simple and easy to follow, this function allows the colour to be set by passing in the RGB value in HEX

 

void infinionSetColour(Colours colour)
{
  colourMode = cSOLID;
  RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0FFF);
  RGBLEDS.SETCOLOUR(colour );
}

this function on the other hand takes an enumeration value as input and translates this to the RGB value by calling the library function RGBLEDS.SETCOLOUR(colour), I know there is not much here but you have to agree it make the upper code far easier to understand by wrapping the details into a function

 

void infinionFLASH()
{
  if (millis() >= nextFlash + flashTime)
  {
    if (isBright )
    {
      RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0000);
      isBright = false;
    }
    else
    {
      RGBLEDS.I2CWRITE2BYTES (ADDRESS, DIMMINGLEVEL, 0x0FFF);
      isBright = true;
    }
    nextFlash = millis();
  }
}

lastly the above function shows how the Infineon shield built in functionality can be used to to manipulate the LEDs without having to touch the basic colour settings. This function simply flashes the LEDs in what ever colour they happen to be in (Does not change them or care what it is currently set to) and simply varies the dimming level as a separate and independent value on the shield. The micro controller on the shield takes care of the rest, even adding nice graceful transitions from one intensity to the other if the board has been configured with a FADERATE property.

 

Thats pretty much it for the code walk through, I hope this helps you to get to grips with your Infineon card and remember, keep your code tidy if you can and modularize often, you will thank yourself later

Back to initial blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

And so all good things come to an end and so it is for this project, as a final entry I present the end solution in its completion

 

The BYOB Party Night

 



As with so many who are putting in a real attempt at this holiday challenge , this has taken way more time than I expected (Probably well over a hundred hours maybe even twice that) but it has been a blast, loads learned, new friends made and hopefully those following along at home are learning allot of new stuff from the various posts from all the participants

 

For those who held back from applying, next time give it a go, some of use go overboard for fun, why... because we can but we try to make it educational and hopefully exciting, the reason for so many hours is we try so many alternative approaches and ideas before we settle on the one we want to present,we select ideas and approaches that others can follow without getting too expensive or complicated and as I think everyone on this project will agree, co-operation and sharing has gone a long way to make this one in my opinion, one of the best yet

 

For everyone reaching the finishing line, well done, you stayed the course, congratulations and I hope you had as much fun as I have, I cant wait to see all the final posts

 

I hope the co-operation continues through 2015 and beyond

 

The following diagram shows all the moving parts (As they say) of the BYOB Party, all of this will be shown working (At the same time) in the video I am currently editing to add to this, all code will also be shared via this blog page for you to use as you feel you want. (No Warranties )

Unfortunately looks can be deceiving, the pictures below make it look way simpler that it was, getting all this hardware to co-operate and talk to each other was not an easy task to start, once I had figured out the approach and waded through the bugs, it all came together. I hope you enjoy.

No Minions where harmed in the making of this project, though MANY where created or crashed the party

STAR.jpg

Some shots videos of individual displays

Hi there

 

In my initial blog post I suggested it would be good to not only have way more than the boards provided by the challange (UNO, YUN and Infinion) but also to mix it up a bit by introducing a foreigner into the mix

 

well I did, in the form of a TI launchpad CC3200

launchpad-cc3200-launchxl-thumbP1010361.jpgP1010362.jpg

This board has WIFI, full IO, 80Mhz MPU and a whole bunch more

 

The design goal is to have this board subscribe to its topics directly rather than relying on Mrs YUN and also to provide value while at the party by monitoring the temperature and reporting it through the Eclipse MQTT broker, all this while running on battery power...

 

This effectively shows that no matte the underlying technology, it is a straight forward task to get them all talking to each other reliably and effectively, this board is subscribing to topics published by the Arduinos in the challenge and also providing value to the mix tha can also be consumed by any technology, in this challenge it was a hardware less node... the WEB browser page use to control the party

 

my initial endevour was to use CCS (Code Composer Studio ) running the TO_RTOS (Real time Operating System) and have several tasks running, one to announce the temperature at the venue and one to highlight the remote guests as they arrive or are pinged via the element14_IoT topic on the PAHO / Ellipse broker

 

This proved to be much harder a learning curve than I anticipated and while I could easily get the addition of one or the other working in the RTOS, it proved impossible for now to get them both working, there is a steep learning curve to get to grips with the RTOS and also the simple link networking stack. alas it got the better of me and I eventually switch to Energia to complete the coding. I will circle back to this once I am more familuar with the required RTOS and Simplelink software, there are many hours of videos to go though first and as I had no responses from my calls to the experts I had to change.

 

So, using Energia is was a simple matter of finding the libraries for MQTT (PubSubClient.h) modified for the CC3200's built in WIFI. I found the library here Creating an IoT-connected sensor with Energia & MQTT | Energia

 

next was to add the ability to both publish and subscribe at the same time as I wanted to include a publication of the temperature sensors included on the launchpad. The current Energia comes with a sample for interfacing with the device from Adafruit but it needs a small tweak to get it running

 

Lastly I also want to control some Higher power LEDs that draw in the region over 300mA and require about 12V to operate, this is way beyond the ability of the control board alone. In my initial breif i also stated I wanted to have relay driven loads that could be up to mains supply voltage. In the interest of safety I decided to not use mains but still retain the relays and instead use these high power LED which is more than good enough to demonstrate the principle of operation (POC at its best ) This is the relay board I used (Only 4 channels needed but I had this already) and this is one set of LEDs to be used.

 

P1010315.JPGP1010316.JPG

 

The other part of this challenge was to have this unit be battery powered... come on down Battery Booster pack, the time is right

med_boostxl-battpack_fuel_tank.jpg

This has been running the board now for over 12 hours and no signs of being flat yet (Its not powering the LEDS but is driving the relays) and between  fvan, mcb1, jancumps and myself peteroakes, were keeping the relays busy .

 

So the code

 

/*
  - connects to an MQTT broker
  - publishes temperature sensor reading to the topic "BYOB-PARTY/PartyTemp and BYOB-PARTY/FloorTemp"
  - also subscribes to the element14_IoT topic and drives outputs based on who is online pinging the topic
  - supports mcb1, fvan, jancumps and peteroakes at the moment
*/


#include <WiFi.h>
#include <Wire.h>
#include "Adafruit_TMP006.h"
#include <PubSubClient.h>
#include <SPI.h> //only required if using an MCU LaunchPad + CC3100 BoosterPack. Not needed for CC3200 LaunchPad
WiFiClient wclient;


byte server[] = { 198, 41, 30, 241 }; //  Public Eclipse MQTT Brokers: http://mqtt.org/wiki/doku.php/public_brokers
byte ip[]     = { 172, 16, 0, 100 }; // gets overridden by the WIFI DHCP


unsigned long timerInterval = 5000; // interval between sensor writes
unsigned long timerNow = millis();// holder for current time to compare to sensorTimer


unsigned long LEDInterval = 10000; // 15 seconds on time
unsigned long LED1On = millis(); // holder for LED1 timer
unsigned long LED2On = millis(); // holder for LED2 timer
unsigned long LED3On = millis(); // holder for LED3 timer
unsigned long LED4On = millis(); // holder for LED4 timer


#define       WIFI_SSID         "xxxxxxxxx"
#define       WIFI_PWD          "xxxxxxxxx"


// Define Outputs
#define LED1 3
#define LED2 4
#define LED3 5
#define LED4 6




Adafruit_TMP006 tmp006(0x41);  // start with a diferent i2c address!


PubSubClient client(server, 1883, callback, wclient);


void callback(char* inTopic, byte* payload, unsigned int length){
  // Handle callback here

  // Allocate the correct amount of memory for the payload copy
  byte* p = (byte*)malloc(length);
  // Copy the payload to the new buffer
  memcpy(p,payload,length);
  p[length]= 0 ; // terminate the string

   Serial.print("Received from topic ");
   Serial.print(inTopic);
   Serial.print(" payload  ");
   Serial.println((char*) p);

  if (strcmp("peteroakes",(char*) p)==0)
  {
   LED1On = millis();
  }
  if (strcmp("jancumps",(char*) p)==0)
  {
   LED2On = millis();
  }
  if (strcmp("mcb1",(char*) p)==0)
  {
   LED3On = millis();
  }
  if (strcmp("fvan",(char*) p)==0)
  {
   LED4On = millis();
  }
  // Free the memory
  free(p);
}


void setup()
{
  //Initialize serial and wait for port to open:
  Serial.begin(115200);


  Serial.println("Start WiFi");
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  while(WiFi.localIP() == INADDR_NONE) {
    Serial.print(".");
    delay(300);
  }
  Serial.println("");


  printWifiStatus();
    if (client.connect("thebreadBoardca")) {
      client.subscribe("element14_IoT");
    }
  timerNow = millis();

  // now spin up the temp sensor
    if (! tmp006.begin()) {
    Serial.println("No sensor found");
    while (1);
  }
    // initialize the digital pin as an output.
  pinMode(LED1, OUTPUT);digitalWrite(LED1, LOW);
  pinMode(LED2, OUTPUT);digitalWrite(LED2, LOW);
  pinMode(LED3, OUTPUT);digitalWrite(LED3, LOW);
  pinMode(LED4, OUTPUT);digitalWrite(LED4, LOW);
}


void loop()
{
if(timerNow + timerInterval  < millis()) {


  // Grab temperature measurements and print them.
  float objt = tmp006.readObjTempC();
  Serial.print("Object Temperature: "); Serial.print(objt); Serial.println("*C");
  float diet = tmp006.readDieTempC();
  Serial.print("Die Temperature: "); Serial.print(diet); Serial.println("*C");


  // convert into to char array
  String strobjt = (String)objt;
  String strdiet = (String)diet;


  int str_len = strobjt.length() + 1;  // Length (with one extra character for the null terminator)
  char char_array[str_len];  // Prepare the character array (the buffer)
  strobjt.toCharArray(char_array, str_len);  // Copy it over

  // publish data to MQTT broker
  client.publish("BYOB-PARTY/PartyTemp", char_array);


  str_len = strdiet.length() + 1;  // Length (with one extra character for the null terminator)
  strdiet.toCharArray(char_array, str_len);  // Copy it over

  // publish data to MQTT broker
  client.publish("BYOB-PARTY/FloorTemp", char_array);


  timerNow = millis(); // reset timer
}
client.loop();

updateLEDS();
}


void updateLEDS()
{
if(millis() - LED1On <= LEDInterval ) {
   // Serial.print("leds 1");
    digitalWrite(LED1, HIGH);
}
else
{
   // Serial.print("leds 0");
   digitalWrite(LED1, LOW);
}
if(millis() - LED2On <= LEDInterval ) {
   // Serial.print(" 1");
   digitalWrite(LED2, HIGH);
}
else
{
   // Serial.print(" 0");
   digitalWrite(LED2, LOW);
}
if(millis() - LED3On <= LEDInterval) {
   // Serial.print(" 1");
   digitalWrite(LED3, HIGH);
}
else
{
   // Serial.print(" 0");
   digitalWrite(LED3, LOW);
}

if(millis() - LED4On <= LEDInterval) {
   // Serial.println(" 1");
   digitalWrite(LED4, HIGH);
}
else
{
   // Serial.println(" 0");
   digitalWrite(LED4, LOW);
}
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());


  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}





 

This does not use the more complex command handling I used for the Arduino based projects, I wanted to show that is can be simple enough with if then else statements where the logic or list of commands is not extensive

 

first thing to note that is typical in the MQTT world of programming is a callback function, in this case literally called "callback", this will catch the messages sent to this device based on the subscriptions it issues, there is a debug print statement to display what is received followed by a series of timer updates based on the message received. Also not that this routine does not directly turn on the LEDs, it does not need to

 

the set-up function is nothing out of the ordinary so ill skip the description for it except to say this is where the subscription call is made to the eclipse.org broker

 

Note in the loop() function that there is a large section of code wrapped with an if statement, this is handling the case of only transmitting the temperature every 1 second rather then every time through the loop. No delay() functions where used or harmed in the making of this code, therefore it is simple to add further functionality without compromising the timing

 

after this loop there is a single call to the client.loop() function, this allows the subscriptions to be checked for data and is required for the mqtt client subscriptions to function

 

lastly in the main loop() there is a call to updateLEDS(), this is where the work is done to determine if any of the LEDs need to be turned on or off

As can be seen from the code, the sequence is repeated for each LED timer and if the timer is active the LED is turned on, if Inactive then it is turned off, this could be optimized to not call the on or off outputs if the state is already there but for this simple code it is not required or necesary

 

That is all there is to this particular project, very simple and effective, the outputs listed above are simply connected to the Relay board and they drive through opto isolators to turn on and of the relays.

Oh, yes there was one other thing, once programmed the board was disconnected from the USB power and supplied by the Battery Booster pack. Works great.

 

One annoying thing I discovered was that during programming, you had to keep removing rto run and replace to program a jumper on the launchpad, i guess this is the one that is used to switch between run time mode and emulation mode, and Energia always programs the runtime flash when programming so while annoying to have to do it, I can understand.

 

Attached is the completed code for you to use as you like

 

Any questions feel free to ask

 

Peter

Back to main blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

This kind of brings back memories from the  "Euro vision Song Contest"

 

Welcome Belgium

Welcome Germany

Welcome Canada...

 

you get the idea

 

so what I wanted to do here was to have a matrix display to show a scrolling sign to say welcome to whom ever publishes their name to the "element14_IoT" topic of the Elclipse MQTT broker

 

I initially tried this using an arduino UNO and could get the display working no problems but there was no room for additional functionality like communications via radio and this was an important feature I wanted

 

over to Light Strip Larry, the MEGA star sports a significant amount of RAM and FLASH space, the Arduino mega was to be driving some WS2812 LED strips but this seemed more appropriate for a MEGA star and could work

 

Adafruit has a great article on getting this up and running on an UNO or MEGA and that part was straight forward, now all I needed was to modify it to handle an NRF24L01 while simultaneously driving a 32*128 pixel array of full colour LEDs, well we got there and this is the resulting code and wiring

 

This is the panel front and back

 

initial Adafruit article can be found here for those wanting to reproduce my project, all the wiring and code are there to get the first level of the project up and running

 

https://learn.adafruit.com/32x16-32x32-rgb-led-matrix

 

This shows the wiring into an UNO, the text is there to tell you the differences when using a MEGA, and yes you have to adhere to them or it will not work, I had to re-configure the NRF24L01 to work around this

 

With an UNO you rapidly run out of pins too which is another good reason to use a MEGA, here are my attempts

P1010331.jpgP1010360.jpg

the additional grey ribbon wire running off to the right on the mega is for the NRF24L01 radio

 

modifying the code was fairly straight forward

 

Adding the additional headers include statements (NRF stuff)

// Bunch of constants in the form of definitions
// 1 = output debug to serial port, 0 = no debug
#define debug 0
/* Include needed Lbraries */
#include <SPI.h>
#include <Wire.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
#include <avr/pgmspace.h>
#include <Infineon.h>
/* End include libraries */
#include <Adafruit_GFX.h>   // Core graphics library
#include <RGBmatrixPanel.h> // Hardware-specific library


 

note there is some code from other IoT-Holiday Lights in there, its been a hectic few weeks and I will eventually get to cleaning it all up

#define CLK 11  // MUST be on PORTB! (Use pin 11 on Mega)


this is the one item you can not ignore when moving to a mega

for the NRF radio I had to use alternate pins as seen in this config statement

RF24 radio(A5, 10);


 

This same code base has been used through many iterations of holiday light modules so most of the commands below can be ignored in this version, only "SETNAME" is used

//Command Strings
PROGMEM const char helloCmd[]     = "Hello";
PROGMEM const char SETNAMECmd[]    = "SETNAME";
PROGMEM const char REDCmd[]      = "RED";
PROGMEM const char GREENCmd[]    = "GREEN";
PROGMEM const char BLUECmd[]     = "BLUE";
PROGMEM const char WHITECmd[]    = "WHITE";
PROGMEM const char FLASHCmd[]    = "FLASH";
PROGMEM const char RAINBOWCmd[]  = "RAINBOW";
PROGMEM const char OFFCmd[]   = "OFF";


 

I was originally going to have the ability to send commands for other cool stuff but ran out of time

 

this is the main loop that monitors the NRF radio, the serial port and refreshes the display in a minimal loop

void loop()
{
  // Notice how the main loop is very simple and the functions
  // seperate the logic into easily manageable parts
  if (CheckSerial())
  {
    DoCommand(inputBuffer, "\0");
  }

  if (CheckNRF())   
  {
    DoCommand(NRFrdata, "\0");
    SendNRFTest(); // echo back command
  }

  doMatrix();
}

 

as you can see, there is a call to check the Serial followed by a call to the Radio followed by a call to update the display, if either of the calls to the radio or serial finds data then it will call the command function passing in the command found

 

Do matrix is the same as found on the Adafruit site so ill not go into details here except where I may make small changes

The DoCommand function is detailed on my tutorials as well no please refer to there for more details  ( Fast Track to Arduino Programming )

the one thing to note is that the case statement calls the setDisplayName function when the command is found, passing in with it any parameters that may also be present. remember that because we are using the NRF radios we have a max of 32bytes we can send including the command without getting into more sophisticated code so we have limits in the messages

    case  SETNAME :         SetDisplayName(Parameter, Parameter2 ); break;

 

so the interesting stuff is in this function

 

void SetDisplayName(char* newName, char* newName2)
{
  sprintf(str, "Happy New Year: %s %s ", newName, newName2);
  //strcpy(str, newName);
  textMin = sizeof(str) * -12;
}

 

As you can see, the changes are pretty simple if you ignore adding the NRF radio stuff and the command processing all of which is explained elsewhere

 

what this does is add the passed in parameters to the function, it inserts it into the greeting file and exists

 

the main routine loop as you recall includes a call to doMatrix(), this function takes care of all the business of the bouncy balls and rendering the text, a pretty neat bit of code and the libraries Adafruit include have all sorts of graphics ability too.

 

You may well ask why even bother with the command which takes away from having a longer message, well if it where omitted then there is a risk of receiving crap from other radios in the vicinity that could mess with the program and later you may want to extend what is done so you may as well have it in from the start

 

Thats pretty much it for this node, a fairly simple one pragmatically speaking and once running can be quite fun to use. As with the whole project, the NRF Radios prooved to be un reliable at anything more than a few feet, this may be due to all the equipment in the area but i will have to investigate that at another time, I have in the past got much better range out of them so I know it can be done. on the other hand, the new range of WIFI boards that sell for only a few $$$ look very interesting and if they proove to be reliable, I may ditch the NRF radios or at least the NRF24L01 versions altogether

 

There is a video in my closing blog that will demonstrate all I have talked about as far as the end functionality and it is quite cool

Back to primary blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

At the very beginning of this project kartben (Benjamin Cabe) kindly provided a demo for using the Infinion RGB Shield and with that demo was a colour wheel web page to remotely manage the output f the RGB LEDs

 

Now while this was a great demo, my plans for world domination my challange needed more, I have utilized at least four separate MQTT topics and some sub topics also.

 

Yes you can submit publications to a topic using an MQTT client installed on your machine or use one of the several test tools out there

 

MQTT SPI or MQTT Lense to name a couple of good ones but these are generic test tools and do there job very well but its not the same as a custom control page to do the job

 

this is what I came up with

 

 

Forgive my lack of graphics skills, I'm a software architect, not a UI designer, I can make things work, I struggle to make them pretty

 

As you can see, most of the page is just logos and stuff, all the interesting parts on on the left side, on to ensure it is still visible to most browsers even of a small screen, secondly as I said im not a graphics UI designer

 

You will recognize the colour wheel of course, I did re-configure it to send to a different topic and also shrink it down a bit

 

This was done by adjusting two files

 

main.js - the java script file loaded up to the browser to help with local code execution

var cw = Raphael.colorwheel($(".colorwheel_small"), 300, 130).color("#00F");
cw.onchange(function(c) {
  color = c;
})



 

Change the code from .colourwheel_large to .colourwheel_small and change the size to 300, note while we are here the declaration of the call back when the wheel is changed, all it will do is set the variable color. we will use this later

 

The file main.css also needs updating as even after these changes the space the wheel ocupied was still massive even though the wheel was now a better size, i tracked this down to a style override in the CSS file

 

/* Responsive: Portrait tablets and up */
@media screen and (min-width: 300px) {
  .container {
    max-width: 300px;
  }



 

look for the above and adjust to the setting your see here, i tried this on several browsers and it worked ok in all cases, originally it was set to 780px or there about. changing just the min-width was not enough, it needed both changing

 

to point he topic to one of my choosing modify the following line

function sendColor() {
  if (connected) {
  if (color != null) {
  var message = new Paho.MQTT.Message(color.toString().replace('#', ''));
  message.destinationName = "theBreadBoard_Strip";
  client.send(message);
  color = null;
  }
  }
}



 

where is says "theBreadBoard_Strip", in the original it is "Benjamin_Strip" or similar, you can change this to suit your needs

 

OK, so now this allows the page to sent to my topic and has freed up some room for more tools

 

I have 4 topics used on my project

 

"theBreadBoard_Strip" to adjust the LED strips connected to my Infinion board, this is covered by the wheel already so nothing more to do on this end except slow it down a bit

"element14_IoT" to ping my system presence for other E14 members, I also subscribe to this to affect change in two of my units as you will see in other blogs

"NeoStar" allows me to control my STAR based on the WS2812 LED chips

"BYOB-PARTY" is used to announce the temperature of the party room and the dance floor (Do I need a jacket, I don't know, why don't I check to see how warm it will be ) this topic also has two sub topics

"BYOB-PARTY/PartyTemp"

"BYOB-PARTY/FloorTemp

 

A single subscription topic of "BYOB-PARTY/#" will capture any changes under the BYOB-PARTY so it saves a subscription. I want to use this topic to display the temperatures on the browser, this means the browser will need to become  an MQTT subscriber, I will need to discover how to do this.

 

First things first, adding the additional publication logic for the Star and the messageing

 

looking at this code in the main.js file you will get an idea how to add functionality

client = new Paho.MQTT.Client("ws://iot.eclipse.org/ws", "id-" + new Date().getTime());

var connected = false;
function onConnect() {
  connected = true;
};


client.connect({
  onSuccess: onConnect
});


looking at the first  line you see the connection being made, the date bit at the end of the line is just to create a random client ID for the connection

next we have a variable to hold the connection status used later in the code

the function "onConnect()" is not called yet, this is the target of a call back when the connection eventually gets established

the code at line 9 above is declaring the call back, as you can see it is passing in the call the name of the call back funtion, once the connection is established, the target function is called and the variable is set.

 

function sendColor() {
  if (connected) {
  if (color != null) {
  var message = new Paho.MQTT.Message(color.toString().replace('#', ''));
  message.destinationName = "theBreadBoard_Strip";
  client.send(message);
  color = null;
  }
  }
}


This is the real working code, it sends the colour to the iot.eclipse.org site for the MQTT broker to process it, the color variable is declared at the top of the file and when this function gets called it will publish the current value but how is it called, glad you ask

 

at the very end of the file you will see this statement

setInterval(sendColor, 100);

 

it is not contained within a function so the page will execute it automatically, it sets up a re-occur timer to call the function in this case every 100mS, you may want to slow this down to say 500mS but it is a user choice

 

so thats how the basic demo page works (Without going into the operation of the wheel etc)

 

now to add my additional functionality

I need 8 buttons, one for each mode the star is programmed for, I inserted this into the HTML Body of the page (I will include as an attachment the complete code so you can see exactly where I put it)

  <table align="center">
        <tr><th style=" color:white ; align-content:center  " >Star Menues</th></tr>
        <tr><td  style="background-color:crimson" class="text-center">
            <input type="button" id="Button10" onclick="sendStar('AUTO')" value="Auto" />
            <input type="button" id="Button1" onclick="sendStar('ROTATE')" value="ROTATE"   />
            <input type="button" id="Button3" onclick="sendStar('ROTATE2')" value="ROTATE2"   />
            <input type="button" id="Button4" onclick="sendStar('EXPAND')" value="EXPAND"  />
        </td></tr>
        <tr><td  style="background-color:crimson" class="text-center">
            <input type="button" id="Button5" onclick="sendStar('EXPAND2')" value="EXPAND2"   />
            <input type="button" id="Button6" onclick="sendStar('CYCLE')" value="CYCLE"   />
            <input type="button" id="Button7" onclick="sendStar('RAINBOW')" value="RAINBOW"  />
            <input type="button" id="Button8" onclick="sendStar('WIPE')" value="WIPE" />
         </td></tr>
        </table>


 

as you can see, every button has an onclick event that calls a function called sendStar("xxx") and passes the function the command we need

the function is simply added to the main.js file

 

here it is

function sendStar(mode) {
    if (connected) {
        starMessage = mode;
        if (starMessage != null) {
            var message = new Paho.MQTT.Message(starMessage.toString());
            message.destinationName = "NeoStar";
            client.send(message);
        }
    }
}


as you can see it is pretty much identical to the color send function. easy right!, not again the use of that "connected" variable to ensure a connection was made before trying to send anything

 

between the HTML and the java script, that adds the functionality needed for the star.

the text sender is equally as simple

 

here is the HTML

     <table align="center" >
        <tr><th style=" color:antiquewhite ; align-content:center  ">Send a message to the Message Board</th></tr>
        <tr><td ><input type="text" id="myText" /><input type="button" id="Button9" onclick="sendText()" value="Send Text" /></td></tr>
    </table>


 

and here is the java function

function sendText() {
    if (connected) {
        dispMessage = document.getElementById("myText").value;
        if (dispMessage != null) {
            var message = new Paho.MQTT.Message(dispMessage.toString());
            message.destinationName = "element14_IoT";
            client.send(message);
        }
    }
}


 

again, almost identical... nice

 

ok so what about the two temperature gauges I showed you in the opening screen shot, that as it happens, ended up relatively simple too once I completed a bit of research

 

I could not easily find the info on the PAHO site but a little google goes a long way

Server send push notifications to client browser without polling | oriolrius.cat

this still uses the PAHO libraries (Well I still stayed with them anyway), needed to perform a little on-screen (In Browser debugging to get it all working properly) but here is the result of the effort

 

at the top of the script where the connection is intially made, we need to add a call back for when messages arrive back from the broker

client = new Paho.MQTT.Client("ws://iot.eclipse.org/ws", "id-" + new Date().getTime());
client.onMessageArrived = onMessageArrived;


 

The "onConnect()" function is added to so the subscription is made automatically when the connected is made

var connected = false;
function onConnect() {
  connected = true;
  client.subscribe("BYOB-PARTY/#", { qos: 1 });
};


 

I simplified the call compared to the material I found and of course added my own topic to the subscription

now of course we need the function to receive the data

function onMessageArrived(message) {
    if (message.destinationName == 'BYOB-PARTY/PartyTemp') {
        // document.getElementById("partytemperature").innerHTML = message.payloadString;
        analog0 = message.payloadString;
    }
    else if (message.destinationName == 'BYOB-PARTY/FloorTemp') {
        //document.getElementById("floortemperature").innerHTML = message.payloadString;
        analog1 = message.payloadString;
    }
};


so this is a little different to the other functions, first of all it required some digging to discover all the additional sub elements of the message structure to allow the topic and content to be extracted, the commented out code was left there to show how to directly target a couple of div takes with IDs declared to receive the updates. I used this to get it working before adding the gauge controls

 

Pay close attention to the checking for the correct topics that the page is interested in, I discovered that there is quite a few calls made to this function in operation, not all with topic data so dont delete the check if your only looking at one topic

 

my function above checks the topic and depending on the one arrived, it will update a variable and then exit. these variables are used by the gauges automatically. I am not going to go into detail regarding the operation of the gauges as this is included in a tutorial set I have posted on the forums. for expediency, I added the scripting for the gauges to the main index.html form

this is the html to add the gauges

    <table align="center">
        <tr>
            <td ><canvas id="Canvas0"></canvas></td>
           <td ><canvas id="Canvas1"></canvas></td>
        </tr>
    </table>


 

the following script is added to the header section of the page and is the libraries so to speek

     <script>
         var Gauge = function (b) {
             function l(a, b) { for (var c in b) "object" == typeof b[c] && "[object Array]" !== Object.prototype.toString.call(b[c]) && "renderTo" != c ? ("object" != typeof a[c] && (a[c] = {}), l(a[c], b[c])) : a[c] = b[c] } function q() { z.width = b.width; z.height = b.height; A = z.cloneNode(!0); B = A.getContext("2d"); C = z.width; D = z.height; t = C / 2; u = D / 2; f = t < u ? t : u; A.i8d = !1; B.translate(t, u); B.save(); a.translate(t, u); a.save() } function v(a) {
                 var b = new Date; G = setInterval(function () {
                     var c = (new Date - b) / a.duration; 1 < c && (c = 1); var f = ("function" ==
   typeof a.delta?a.delta:M[a.delta])(c);a.step(f);1==c&&clearInterval(G)},a.delay||10)}function k(){G&&clearInterval(G);var a=I-n,h=n,c=b.animation;v({delay:c.delay,duration:c.duration,delta:c.fn,step:function(b){n=parseFloat(h)+a*b;E.draw()}})}function e(a){return a*Math.PI/180}function g(b,h,c){c=a.createLinearGradient(0,0,0,c);c.addColorStop(0,b);c.addColorStop(1,h);return c}function p(){var m=93*(f/100),h=f-m,c=91*(f/100),e=88*(f/100),d=85*(f/100);a.save();b.glow&&(a.shadowBlur=h,a.shadowColor=
   "rgba(0, 0, 0, 0.5)");a.beginPath();a.arc(0,0,m,0,2*Math.PI,!0);a.fillStyle=g("#ddd","#aaa",m);a.fill();a.restore();a.beginPath();a.arc(0,0,c,0,2*Math.PI,!0);a.fillStyle=g("#fafafa","#ccc",c);a.fill();a.beginPath();a.arc(0,0,e,0,2*Math.PI,!0);a.fillStyle=g("#eee","#f0f0f0",e);a.fill();a.beginPath();a.arc(0,0,d,0,2*Math.PI,!0);a.fillStyle=b.colors.plate;a.fill();a.save()}function w(a){var h=!1;a=0===b.majorTicksFormat.dec?Math.round(a).toString():a.toFixed(b.majorTicksFormat.dec);return 1<b.majorTicksFormat["int"]?
   (h=-1<a.indexOf("."),-1<a.indexOf("-")?"-"+(b.majorTicksFormat["int"]+b.majorTicksFormat.dec+2+(h?1:0)-a.length)+a.replace("-",""):""+(b.majorTicksFormat["int"]+b.majorTicksFormat.dec+1+(h?1:0)-a.length)+a):a}function d(){var m=81*(f/100);a.lineWidth=2;a.strokeStyle=b.colors.majorTicks;a.save();if(0===b.majorTicks.length){for(var h=(b.maxValue-b.minValue)/5,c=0;5>c;c++)b.majorTicks.push(w(b.minValue+h*c));b.majorTicks.push(w(b.maxValue))}for(c=0;c<b.majorTicks.length;++c)a.rotate(e(45+c*(270/(b.majorTicks.length-
   1)))),a.beginPath(),a.moveTo(0,m),a.lineTo(0,m-15*(f/100)),a.stroke(),a.restore(),a.save();b.strokeTicks&&(a.rotate(e(90)),a.beginPath(),a.arc(0,0,m,e(45),e(315),!1),a.stroke(),a.restore(),a.save())}function J(){var m=81*(f/100);a.lineWidth=1;a.strokeStyle=b.colors.minorTicks;a.save();for(var h=b.minorTicks*(b.majorTicks.length-1),c=0;c<h;++c)a.rotate(e(45+c*(270/h))),a.beginPath(),a.moveTo(0,m),a.lineTo(0,m-7.5*(f/100)),a.stroke(),a.restore(),a.save()}function s(){for(var m=55*(f/100),h=0;h<b.majorTicks.length;++h){var c=
   F(m,e(45+h*(270/(b.majorTicks.length-1))));a.font=20*(f/200)+"px Arial";a.fillStyle=b.colors.numbers;a.lineWidth=0;a.textAlign="center";a.fillText(b.majorTicks[h],c.x,c.y+3)}}function x(a){var h=b.valueFormat.dec,c=b.valueFormat["int"];a=parseFloat(a);var f=0>a;a=Math.abs(a);if(0<h){a=a.toFixed(h).toString().split(".");h=0;for(c-=a[0].length;h<c;++h)a[0]="0"+a[0];a=(f?"-":"")+a[0]+"."+a[1]}else{a=Math.round(a).toString();h=0;for(c-=a.length;h<c;++h)a="0"+a;a=(f?"-":"")+a}return a}function F(a,b){var c=
   Math.sin(b),f=Math.cos(b);return{x:0*f-a*c,y:0*c+a*f}}function N(){a.save();for(var m=81*(f/100),h=m-15*(f/100),c=0,g=b.highlights.length;c<g;c++){var d=b.highlights[c],r=(b.maxValue-b.minValue)/270,k=e(45+(d.from-b.minValue)/r),r=e(45+(d.to-b.minValue)/r);a.beginPath();a.rotate(e(90));a.arc(0,0,m,k,r,!1);a.restore();a.save();var l=F(h,k),p=F(m,k);a.moveTo(l.x,l.y);a.lineTo(p.x,p.y);var p=F(m,r),n=F(h,r);a.lineTo(p.x,p.y);a.lineTo(n.x,n.y);a.lineTo(l.x,l.y);a.closePath();a.fillStyle=d.color;a.fill();
       a.beginPath();a.rotate(e(90));a.arc(0,0,h,k-0.2,r+0.2,!1);a.restore();a.closePath();a.fillStyle=b.colors.plate;a.fill();a.save()}}function K(){var m=12*(f/100),h=8*(f/100),c=77*(f/100),d=20*(f/100),k=4*(f/100),r=2*(f/100),l=function(){a.shadowOffsetX=2;a.shadowOffsetY=2;a.shadowBlur=10;a.shadowColor="rgba(188, 143, 143, 0.45)"};l();a.save();n=0>n?Math.abs(b.minValue-n):0<b.minValue?n-b.minValue:Math.abs(b.minValue)+n;a.rotate(e(45+n/((b.maxValue-b.minValue)/270)));a.beginPath();a.moveTo(-r,-d);a.lineTo(-k,
       0);a.lineTo(-1,c);a.lineTo(1,c);a.lineTo(k,0);a.lineTo(r,-d);a.closePath();a.fillStyle=g(b.colors.needle.start,b.colors.needle.end,c-d);a.fill();a.beginPath();a.lineTo(-0.5,c);a.lineTo(-1,c);a.lineTo(-k,0);a.lineTo(-r,-d);a.lineTo(r/2-2,-d);a.closePath();a.fillStyle="rgba(255, 255, 255, 0.2)";a.fill();a.restore();l();a.beginPath();a.arc(0,0,m,0,2*Math.PI,!0);a.fillStyle=g("#f0f0f0","#ccc",m);a.fill();a.restore();a.beginPath();a.arc(0,0,h,0,2*Math.PI,!0);a.fillStyle=g("#e8e8e8","#f5f5f5",h);a.fill()}
             function L(){a.save();a.font=40*(f/200)+"px Led";var b=x(y),h=a.measureText("-"+x(0)).width,c=f-33*(f/100),g=0.12*f;a.save();var d=-h/2-0.025*f,e=c-g-0.04*f,h=h+0.05*f,g=g+0.07*f,k=0.025*f;a.beginPath();a.moveTo(d+k,e);a.lineTo(d+h-k,e);a.quadraticCurveTo(d+h,e,d+h,e+k);a.lineTo(d+h,e+g-k);a.quadraticCurveTo(d+h,e+g,d+h-k,e+g);a.lineTo(d+k,e+g);a.quadraticCurveTo(d,e+g,d,e+g-k);a.lineTo(d,e+k);a.quadraticCurveTo(d,e,d+k,e);a.closePath();d=a.createRadialGradient(0,c-0.12*f-0.025*f+(0.12*f+0.045*f)/
             2,f/10,0,c-0.12*f-0.025*f+(0.12*f+0.045*f)/2,f/5);d.addColorStop(0,"#888");d.addColorStop(1,"#666");a.strokeStyle=d;a.lineWidth=0.05*f;a.stroke();a.shadowBlur=0.012*f;a.shadowColor="rgba(0, 0, 0, 1)";a.fillStyle="#babab2";a.fill();a.restore();a.shadowOffsetX=0.004*f;a.shadowOffsetY=0.004*f;a.shadowBlur=0.012*f;a.shadowColor="rgba(0, 0, 0, 0.3)";a.fillStyle="#444";a.textAlign="center";a.fillText(b,-0,c);a.restore()}Gauge.Collection.push(this);this.config={renderTo:null,width:200,height:200,title:!1,
                 maxValue:100,minValue:0,majorTicks:[],minorTicks:10,strokeTicks:!0,units:!1,valueFormat:{"int":3,dec:2},majorTicksFormat:{"int":1,dec:0},glow:!0,animation:{delay:10,duration:250,fn:"cycle"},colors:{plate:"#fff",majorTicks:"#444",minorTicks:"#666",title:"#888",units:"#888",numbers:"#444",needle:{start:"rgba(240, 128, 128, 1)",end:"rgba(255, 160, 122, .9)"}},highlights:[{from:20,to:60,color:"#eee"},{from:60,to:80,color:"#ccc"},{from:80,to:100,color:"#999"}]};var y=0,E=this,n=0,I=0,H=!1;this.setValue=
                 function(a){n=b.animation?y:a;var d=(b.maxValue-b.minValue)/100;I=a>b.maxValue?b.maxValue+d:a<b.minValue?b.minValue-d:a;y=a;b.animation?k():this.draw();return this};this.setRawValue=function(a){n=y=a;this.draw();return this};this.clear=function(){y=n=I=this.config.minValue;this.draw();return this};this.getValue=function(){return y};this.onready=function(){};l(this.config,b);this.config.minValue=parseFloat(this.config.minValue);this.config.maxValue=parseFloat(this.config.maxValue);b=this.config;n=
                 y=b.minValue;if(!b.renderTo)throw Error("Canvas element was not specified when creating the Gauge object!");var z=b.renderTo.tagName?b.renderTo:document.getElementById(b.renderTo),a=z.getContext("2d"),A,C,D,t,u,f,B;q();this.updateConfig=function(a){l(this.config,a);q();this.draw();return this};var M={linear:function(a){return a},quad:function(a){return Math.pow(a,2)},quint:function(a){return Math.pow(a,5)},cycle:function(a){return 1-Math.sin(Math.acos(a))},bounce:function(a){a:{a=1-a;for(var b=0,
                 c=1;;b+=c,c/=2)if(a>=(7-4*b)/11){a=-Math.pow((11-6*b-11*a)/4,2)+Math.pow(c,2);break a}a=void 0}return 1-a},elastic:function(a){a=1-a;return 1-Math.pow(2,10*(a-1))*Math.cos(30*Math.PI/3*a)}},G=null;a.lineCap="round";this.draw=function(){if(!A.i8d){B.clearRect(-t,-u,C,D);B.save();var g={ctx:a};a=B;p();N();J();d();s();b.title&&(a.save(),a.font=24*(f/200)+"px Arial",a.fillStyle=b.colors.title,a.textAlign="center",a.fillText(b.title,0,-f/4.25),a.restore());b.units&&(a.save(),a.font=22*(f/200)+"px Arial",
                 a.fillStyle=b.colors.units,a.textAlign="center",a.fillText(b.units,0,f/3.25),a.restore());A.i8d=!0;a=g.ctx;delete g.ctx}a.clearRect(-t,-u,C,D);a.save();a.drawImage(A,-t,-u,C,D);if(Gauge.initialized)L(),K(),H||(E.onready&&E.onready(),H=!0);else var e=setInterval(function(){Gauge.initialized&&(clearInterval(e),L(),K(),H||(E.onready&&E.onready(),H=!0))},10);return this}};Gauge.initialized=!1;
         (function(){var b=document,l=b.getElementsByTagName("head")[0],q=-1!=navigator.userAgent.toLocaleLowerCase().indexOf("msie"),v="@font-face {font-family: 'Led';src: url('fonts/digital-7-mono."+(q?"eot":"ttf")+"');}",k=b.createElement("style");k.type="text/css";if(q)l.appendChild(k),l=k.styleSheet,l.cssText=v;else{try{k.appendChild(b.createTextNode(v))}catch(e){k.cssText=v}l.appendChild(k);l=k.styleSheet?k.styleSheet:k.sheet||b.styleSheets[b.styleSheets.length-1]}var g=setInterval(function(){if(b.body){clearInterval(g);
             var e=b.createElement("div");e.style.fontFamily="Led";e.style.position="absolute";e.style.height=e.style.width=0;e.style.overflow="hidden";e.innerHTML=".";b.body.appendChild(e);setTimeout(function(){Gauge.initialized=!0;e.parentNode.removeChild(e)},250)}},1)})();Gauge.Collection=[];
         Gauge.Collection.get=function(b){if("string"==typeof b)for(var l=0,q=this.length;l<q;l++){if((this[l].config.renderTo.tagName?this[l].config.renderTo:document.getElementById(this[l].config.renderTo)).getAttribute("id")==b)return this[l]}else return"number"==typeof b?this[b]:null};function domReady(b){window.addEventListener?window.addEventListener("DOMContentLoaded",b,!1):window.attachEvent("onload",b)}
         domReady(function(){function b(b){for(var e=b[0],d=1,g=b.length;d<g;d++)e+=b[d].substr(0,1).toUpperCase()+b[d].substr(1,b[d].length-1);return e}for(var l=document.getElementsByTagName("canvas"),q=0,v=l.length;q<v;q++)if("canv-gauge"==l[q].getAttribute("data-type")){var k=l[q],e={},g,p=parseInt(k.getAttribute("width"),10),w=parseInt(k.getAttribute("height"),10);e.renderTo=k;p&&(e.width=p);w&&(e.height=w);p=0;for(w=k.attributes.length;p<w;p++)if(g=k.attributes.item(p).nodeName,"data-type"!=g&&"data-"==
         g.substr(0,5)){var d=g.substr(5,g.length-5).toLowerCase().split("-");if(g=k.getAttribute(g))switch(d[0]){case "colors":d[1]&&(e.colors||(e.colors={}),"needle"==d[1]?(d=g.split(/\s+/),e.colors.needle=d[0]&&d[1]?{start:d[0],end:d[1]}:g):(d.shift(),e.colors[b(d)]=g));break;case "highlights":e.highlights||(e.highlights=[]);g=g.split(",");for(var d=0,J=g.length;d<J;d++){var s=g[d].replace(/^\s+|\s+$/g,"").split(/\s+/),x={};s[0]&&""!=s[0]&&(x.from=s[0]);s[1]&&""!=s[1]&&(x.to=s[1]);s[2]&&""!=s[2]&&(x.color=
         s[2]);e.highlights.push(x)}break;case "animation":d[1]&&(e.animation||(e.animation={}),"fn"==d[1]&&/^\s*function\s*\(/.test(g)&&(g=eval("("+g+")")),e.animation[d[1]]=g);break;default:d=b(d);if("onready"==d)continue;if("majorTicks"==d)g=g.split(/\s+/);else if("strokeTicks"==d||"glow"==d)g="true"==g?!0:!1;else if("valueFormat"==d)if(g=g.split("."),2==g.length)g={"int":parseInt(g[0],10),dec:parseInt(g[1],10)};else continue;e[d]=g}}e=new Gauge(e);k.getAttribute("data-value")&&e.setRawValue(parseFloat(k.getAttribute("data-value")));
             k.getAttribute("data-onready")&&(e.onready=function(){eval(this.config.renderTo.getAttribute("data-onready"))});e.draw()}});window.Gauge=Gauge;
       
    </script>
    <style type="text/css">
    .centerText{
   text-align: center;
}
    .divBorder {
    border: 2px solid;
    border-radius: 15px;
    width: 810px;
    text-align: center;
    box-shadow: 6px 6px 3px #888888
}
    .myRange {
    border: 2px solid;
    height: 10px;
    display: block;
    margin: 20px;
    vertical-align: middle;
    text-align: center;
    border-radius: 5px;
    background-color: #444;
    box-shadow: 6px 6px 3px #888888
}


        .auto-style3 {
            width: 123px;
            height: 28px;
        }
        .auto-style4 {
            height: 28px;
        }
        .auto-style6 {
            width: 149px;
            text-align: center;
        }


    </style>


 

below the added HTML we also need the script to configure and activate the gauges

<script>
     var gauge0 = new Gauge({
         renderTo: 'Canvas0',
         width: 200, height: 200,
         maxValue: 100,
         valueFormat: { int: 2, dec: 2 },
         glow: true,
         units: 'Deg C', title: 'Party Room',
         majorTicks: ['0', '20', '40', '60', '80', '100'],
         strokeTicks: true,
         highlights: [{from: 00,to: 20,color: 'PaleGreen'}, {from: 20,to: 60,color: 'Khaki'}, {from: 60,to: 100,color: 'LightSalmon'}],
         animation: {delay: 10, duration: 300,fn: 'bounce' }
     });
     gauge0.onready = function () { setInterval(function () { gauge0.setValue(analog0); }, 1000); };
     gauge0.draw();


     var gauge1 = new Gauge({
         renderTo: 'Canvas1',
         width: 200, height: 200,
         maxValue: 100,
         units: 'Deg C', title: 'Dance Floor',
         valueFormat: { int: 2, dec: 2 },
         glow: true,
         majorTicks: ['0', '20', '40', '60', '80', '100'],
         strokeTicks: true,
         highlights: [{ from: 00, to: 20, color: 'PaleGreen' }, { from: 20, to: 60, color: 'Khaki' }, { from: 60, to: 100, color: 'LightSalmon' }],
         animation: { delay: 10, duration: 300, fn: 'bounce' }
     });
     gauge1.onready = function () {setInterval(function () {gauge1.setValue(analog1);}, 1000);};
     gauge1.draw();
</script>


This is where you get to configure the gauges as you need, in my case, setting the size, the range of the ticks and the format of the data.

the gauge1.onready functions activate the gauges and set a timer (1000) once a second in this case and as you can see, the analog variable mentioned above is now used to pass in the current value, the nice thing here is that the receiving of MQTT data and the updating of the gauge is completely separated making the code more stable and responsive.

 

and thats all there is too it, simple right (Well straight forward anyway)

 

if you have questions, please ask, dont be afraid to try this

 

Oh and the best thing of all, this complete web solution was hosted by the Arduino YUN itself, you dont have to expose your web pages to the outside world if you dont want to, of course if you do you can, and infact Cabe's demo was hosted right from his GIT source site... sweet.

 

I will attach the complete set-up for the yun as a zip file, simply extract it and save to the root of the uSD card to go into the yu,  the rest is simple, browse to arduino.local/sd and your page will appear

 

you should end up with an Arduino folder in the root of the SD card

Back to the primary blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

OK, so in the last post you where treated to my first attempt at re-flow soldering in an attempt to get my WS2812 LEDS ready for my Holiday Light decoration

 

Now I have completed a bit of the wiring and have the initial display code up and running, I would like to share some of the effects, i will include the code as you may find it handy for your own projects, I will update it once the NRF Radio software is added so you can issue remote commands and tie t into the MQTT subscription system

 

Step one is to break apart the strips along the v groves and adding the needed wiring prior to adding to their enclosure

 

I chose to award this display to another Arduino for now and so the next step was to add additional effects to the code to make this allot more interesting display.

 

Step two, find the enclosure (My personal favourite bit )

 

The enclosure for the project is simply a choc box (I'm all for re-cycling stuff where I can )

 

Start with a preferably full box of chocolates, Star shaped like this one

After eating all the stuff inside (Well we need the box empty for this project right ) you will see that the two halves of the box fit nicely into each other, well keep one part ccompletely intact and take the base out of the other leaving only the sides

P1010354.JPG

the now floppy sides will fit nicely into the inside of the other half with a little bit of cutting and glueing, leaving you with a nice partitioned enclosure for the lights

P1010355.JPG

The minions are helping out keep thins in place while glue dries (I personally think they just wanted a nap), make sure to include a big enough hole in the centre to pass wires through

Pre wire the strips ready to install into the case

P1010356.JPG

break apart the boards and install into the star passing the wires through the hole in the centre

P1010358.JPG

now on the back, connect all the power leads together  and connect the data in pins of the next strip to the previous data out connection, secure all the joints and were done the wiring

P1010359.JPG

Load up software into the uno, connect 5V to the lights, and a single data line to pin 6 of the uno and were all set to test.

 

Here is the test video

 

I hope you like it, I will follow up once the software is ready for the party radio

also here is the code so far in-case you would like to use it on your project

Back to primary BLOG BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

 

This is a quick blog to share my experience with trying to solder some WS2812 6pin LED chips onto my custom boards

 

I have about 14 strips to solder up and each strip contains 10 LED modules, the last time I tried to solder these, I had more fail than ended up on the board so I was determined to find a better way

 

So what I have is this

 

TEFAL Convection toaster oven I picked up new but on a big time sale at the local hardware store

Tubes of Solder paste

bunch of WS2812 LEDs to solder that are a PITB to solder by hand

NO Stencil for for the soldering

 

bunch of boards waiting for the LEDS

P1010322.JPG

 

So I have been meaning to give the Oven a try after I had converted the controller to something designed for re-flow, alas time was against me so I decided to see how easy it is without all the fancy controls

 

Well as it turned out and as you will see in the video, it was actually quite easy (Well the re-flow part anyway), the application of the solder paste was a pain without a solder mask and my first attempts with a small flat screwdriver ended up with loads of bridges I had to clean up with solder wick

 

Second attempy was using an old needle from an INK refill system I had long abandoned but happened to fit nicely onto the end of the syringe containing the solder, it took some strength to squeeze it out of he tube with it did allow much finer control of the application, more practice is needed though to get proficient at it.

 

At the end of the day, the effort was worth it and I now have six boards competed with seven more to do and only had a few bridges on the second attempt which was 5 strips at once

 

I have one faulty LED where the red led is not working, once im done with the remaining board, if i have spare LEDs i will replace it, till then it will have to stay

 

this is the heat profile I used, simply the timer on my camera and an Agilent DMM with a thermocouple, very easy and simple to repeat

 

 

here is the video

 

and thats all there is too it, now to get the next party goer kitted out for the pending bash

This time we have a sneak peak at the PI household to see their preparations for the BYOB Party

 

raspberry_pi_raspanimated.gif

 

Mr PI, not to be outdone by the young whipper-snapper Mr UNO Mrs Yun decided to have a crack at driving a couple of those fancy LED matrix panels from Adafruit, the idea being that messages can be posted to the iot.eclipse.org MQTT Broker and mr PI would subscribe to them and display the data (Messages) on the matrix display in glorious colour

 

Having all that extra memory allows the PI to calculate the patterns for much bigger displays but I was concerned that the timing may be an issue, after all, PI struggles even with a simple WS2812B neopixel.

 

Well as it happens I need not have been concerned, the timing on these boards is pretty straight forward and really only affects the refresh rate, not the actual clocking of the data to the display

 

The boards work a bit like a TV, well not quite but you'll see what I mean

these particular boards have two sets of serial data inputs, consisting of an R, G, B data line for each serial channel, a clock line to control the data feed and an Output enable / Latch to lock in the data and display on the LEDs

 

you clock as many pixels as there are in a row (up to 3 bytes per pixel) so 32 pixels = 92, 184 if you count both panels as the serial out from one feeds into the serial in of the next. The boards can be extended as far as needed, the cpu just needs to be able to clock out the data fast enough to keep up a decent refresh rate

 

there are 3 address lines permitting sending the RGB data to one of 8 LED rows (Remember there are two channels of RGB so we cover the 16 rows with 8 addresses and two serial streams), so the best refresh rate of a line is one in 8

 

if your using more than one board daisy chained then you simply clock out more data before firing the latch line

 

that's all there is to it basically.

 

So Adafruit has done an awesome job of creating a library to support these boards and you can download it from their site ( here: https://learn.adafruit.com/connecting-a-16x32-rgb-led-matrix-panel-to-a-raspberry-pi/overview

and part two where the topic adds additional boards in cascade https://learn.adafruit.com/16x32-rgb-display-with-raspberry-pi-part-2

 

there is a nice set of instructions on how to wire up the PI to the panels and plenty of sample code that can run the boards

 

raspberry_pi_wiring_diagram.png

 

Code is a C module and there is also Python samples

 

additional help can be found here https://github.com/Boomerific/rpi-rgb-led-matrix

 

there are a lot of wires used to connect the matrix panels but this is no different no matter the controller your using.

 

for example this is an easy to follow Python sample

import RPi.GPIO as GPIO
import time
 
delay = 0.000001
 
GPIO.setmode(GPIO.BCM)
red1_pin = 17
green1_pin = 18
blue1_pin = 22
red2_pin = 23
green2_pin = 24
blue2_pin = 25
clock_pin = 3
a_pin = 7
b_pin = 8
c_pin = 9
latch_pin = 4
oe_pin = 2
 
GPIO.setup(red1_pin, GPIO.OUT)
GPIO.setup(green1_pin, GPIO.OUT)
GPIO.setup(blue1_pin, GPIO.OUT)
GPIO.setup(red2_pin, GPIO.OUT)
GPIO.setup(green2_pin, GPIO.OUT)
GPIO.setup(blue2_pin, GPIO.OUT)
GPIO.setup(clock_pin, GPIO.OUT)
GPIO.setup(a_pin, GPIO.OUT)
GPIO.setup(b_pin, GPIO.OUT)
GPIO.setup(c_pin, GPIO.OUT)
GPIO.setup(latch_pin, GPIO.OUT)
GPIO.setup(oe_pin, GPIO.OUT)
 
screen = [[0 for x in xrange(32)] for x in xrange(16)]
 
def clock():
  GPIO.output(clock_pin, 1)
  GPIO.output(clock_pin, 0)
 
def latch():
  GPIO.output(latch_pin, 1)
  GPIO.output(latch_pin, 0)
 
def bits_from_int(x):
  a_bit = x & 1
  b_bit = x & 2
  c_bit = x & 4
   return (a_bit, b_bit, c_bit)
 
def set_row(row):
   #time.sleep(delay)
  a_bit, b_bit, c_bit = bits_from_int(row)
  GPIO.output(a_pin, a_bit)
  GPIO.output(b_pin, b_bit)
  GPIO.output(c_pin, c_bit)
   #time.sleep(delay)
 
def set_color_top(color):
   #time.sleep(delay)
  red, green, blue = bits_from_int(color)
  GPIO.output(red1_pin, red)
  GPIO.output(green1_pin, green)
  GPIO.output(blue1_pin, blue)
   #time.sleep(delay)
 
def set_color_bottom(color):
   #time.sleep(delay)
  red, green, blue = bits_from_int(color)
  GPIO.output(red2_pin, red)
  GPIO.output(green2_pin, green)
  GPIO.output(blue2_pin, blue)
   #time.sleep(delay)
 
def refresh():
   for row in range(8):
  GPIO.output(oe_pin, 1)
  set_color_top(0)
  set_row(row)
   #time.sleep(delay)
   for col in range(32):
  set_color_top(screen[row][col])
  set_color_bottom(screen[row+8][col])
  clock()
   #GPIO.output(oe_pin, 0)
  latch()
  GPIO.output(oe_pin, 0)
  time.sleep(delay)
 
def fill_rectangle(x1, y1, x2, y2, color):
   for x in range(x1, x2):
   for y in range(y1, y2):
  screen[y][x] = color
 
 
def set_pixel(x, y, color):
  screen[y][x] = color
 
fill_rectangle(0, 0, 12, 12, 1)
fill_rectangle(20, 4, 30, 15, 2)
fill_rectangle(15, 0, 19, 7, 7)
 
while True:
  refresh()



if you have not already updated or installed Python, now would be a good time

 

this is the code I used finally for the messages, it is a relatively

import os
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
 
text = (("Raspberry Pi ", (255, 0, 0)), ("and ", (0, 255, 0)), ("Adafruit", (0, 0, 255)))
 
 
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeSans.ttf", 16)
all_text = ""
for text_color_pair in text:
  t = text_color_pair[0]
  all_text = all_text + t
 
print(all_text)
width, ignore = font.getsize(all_text)
print(width)
 
 
im = Image.new("RGB", (width + 30, 16), "black")
draw = ImageDraw.Draw(im)
 
x = 0;
for text_color_pair in text:
  t = text_color_pair[0]
  c = text_color_pair[1]
   print("t=" + t + " " + str(c) + " " + str(x))
  draw.text((x, 0), t, c, font=font)
  x = x + font.getsize(t)[0]
 
im.save("test.ppm")
 
os.system("./led-matrix 1 test.ppm")

easy task to change the message to one you like (Look for this line "text = (("Raspberry Pi ", (255, 0, 0)), ("and ", (0, 255, 0)), ("Adafruit", (0, 0, 255)))"  )

 

What I am planning to do is to have the PI subscribe to the elcipse mqtt broker with a specific topic "BreadBoard_Messages" and as messages are published, a modified version of the code will create the required image and then render and scroll it across the panels.

 

This will allow party messages or tweets to be received and shown during the BYOB  Party, My PI may not be able to interact too much but if he can pull this off it will be a great feat and useful in the future too

 

here is a short video demonstrating the PI driving a couple of the panels

 

in the next post I hope to have the code ready to read from the subscription data and render as an animated display in near real time

 

that's where I have challenged my son to help, integrate two sets of code into one great application

 

Ill be back with the results in a few days on this one

 

See you soon

The the Minions have been busy educating Trinket and as of now have indoctrinated him into the minion union,

 

This....Is....The....First....BIOMINIONOID.

 

Meet BOB

 

P1010353.JPG

 

Bob is new, he is improved, he is the first Bionic Minion, he is still a baby, Oh ya, he may be bigger than his buds but he has a long way to evolve but he is aware of his surroundings, and he is ready for the BYOB Party, the minions will keep him safe and under control so all is good

 

between the HR-S501 motion detector, the HC-SR04 ultrasonic sensor and those goggles, he is awesome

 

so what makes him tick

 

his heart, small as it may be has loads of power, an ATTINY 85 with 8K flash running at 16Mhz, a few IO pins and built in USB capability

 

as much as the minions tried, he only has a limited capacity and so only has a few tricks

 

He will wake up if he senses movement from over 20 feet away, he will wake up and look around with those wonderful green eyes of his

 

If you get within a couple of feet he will see you and put on a pretty light show, but dont be fooled, get too close and he may think your after his sucker and will shows his anger by turning his eyes RED, just back away and he will calm down, get out of sight and he will go back to sleep

 

there are only 8 pins on an ATTINY85 so here's how they where used:

2 pins for power

2 pins taken with the ultrasonic sensor

1 pin with the PIR

1 pin to drive the WS2812 LED strings in two circles of 16 (32 in total)

1 pin for reset

1 pin spare but coupled with the USB so not easy to use for anything

 

The minions could not educate Bob as much as they would like as they where exceeding his capacity but they did a pretty good job

 

here is the video

 

So the fun was to integrate the NEOPIXELS, the Ultrasonic Sensor and the PIR to the ATTINY85 but still be able to upload the code (The Trinket takes a couple of K to provide a boot loader via USB so this only leaves a little over 5K), It still has one pin available but with a 1.5K pullup, the PIR had a hard time grounding when using pin 3 it so I had to move to using pin 0. Pin 3 is available for perhaps a switch but there is no code space remaining given the current memory usage because of the boot loader.

 

At the end of the day I was able to squeeze everything in but at a reduced set of patterns on the neopixels, no room for even additional if statements.

 

here is the software (Attached for easy copying if so desired)

/*
NeoPixel Ring goggles sketch -- for steampunk, rave or Burning Man fashion!
Welding or costume goggles using 50mm round lenses can be outfitted with
a pair of Adafruit NeoPixel Rings: http://www.adafruit.com/product/1463


Please exercise common sense.  These goggles emit a LOT of stray light and
should NOT BE WORN ON YOUR EYES.  They're for fashion and costuming only,
for display on a hat or on your forehead.


Draws a spinning rainbow on both eyepieces.  Not a Mac beachball, honest.
"Eyes" glance around and blink at random.


For 'reflected' colors (rainbows rotate in opposite directions, while eyes
look in same direction), connect the output of the first ring to the input
of the second.  Or you can connect the inputs of both rings to the same
Arduino pin if that's easier -- the rainbows will both twirl in the same
direction in that case.


By default, pixel #0 (the first LED) on both rings should be at the TOP of
the goggles.  Looking at the BACK of the board, pixel #0 is immediately
clockwise from the OUT connection.  If a different pixel is at the top,
that's OK, the code can compensate (TOP_LED_FIRST and TOP_LED_SECOND below).


Modified by Peter Oakes to add a couple extra patterns, motion and range sensors
to trigger the wakeup of the rings and to to sleep with inactivity
*/


#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
  #include <avr/power.h>
#endif


#define PIN            4
#define PIR            0 // PIR input pin
#define trigPin        2 // UNLTRA Trigger pin
#define echoPin        1 // echo back pin


#define TOP_LED_FIRST  0 // Change these if the first pixel is not
#define TOP_LED_SECOND 0 // at the top of the first and/or second ring.


#define EFFECT         xECTO // Choose a visual effect from the names below


#define RAINBOW        0
#define ECTO           1


int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration = -1; // Duration used to calculate distance


Adafruit_NeoPixel pixels = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800);


const int8_t PROGMEM
  yCoord[] = { // Vertical coordinate of each pixel.  First pixel is at top.
    127,117,90,49,0,-49,-90,-117,-127,-117,-90,-49,0,49,90,117 },
  sine[] = { // Brightness table for ecto effect
    0, 28, 96, 164, 192, 164, 96, 28, 0, 28, 96, 164, 192, 164, 96, 28 };


// Eyelid vertical coordinates.  Eyes shut slightly below center.
#define upperLidTop     130
#define upperLidBottom  -45
#define lowerLidTop     -40
#define lowerLidBottom -130


// Gamma correction improves appearance of midrange colors
const uint8_t PROGMEM gamma8[] = {
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
      0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,
      1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
      3,  3,  4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  7,
      7,  7,  8,  8,  8,  9,  9,  9, 10, 10, 10, 11, 11, 11, 12, 12,
     13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
     20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29,
     30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42,
     42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
     58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75,
     76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96,
     97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120,
    122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148,
    150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,
    182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215,
    218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255
};


uint32_t
  iColor[16][3];      // Background colors for eyes
int16_t
  hue          =   0; // Initial hue around perimeter (0-1535)
uint8_t
  iBrightness[16],    // Brightness map -- eye colors get scaled by these
  brightness   = 220, // Global brightness (0-255)
  blinkFrames  =   5, // Speed of current blink
  blinkCounter =  30, // Countdown to end of next blink
  eyePos       = 192, // Current 'resting' eye (pupil) position
  newEyePos    = 192, // Next eye position when in motion
  gazeCounter  =  75, // Countdown to next eye movement
  gazeFrames   =  50; // Duration of eye movement (smaller = faster)
int8_t eyeMotion    =   0; // Distance from prior to new position
boolean off = true;


void setup() {
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
  if(F_CPU == 16000000) clock_prescale_set(clock_div_1);
  // Seed random number generator from an unused analog input:
  randomSeed(analogRead(2));
#else
  randomSeed(analogRead(A0));
#endif


pinMode(PIR, INPUT_PULLUP);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);

pixels.begin();
}


void loop() {


  if(digitalRead(PIR) == 1)// wer are awake
  {
    doeffect();
    off = false;
  }
  else
  {
    if (off == false)
    {
      colorWipe(pixels.Color(0, 000, 0), 50); // Off as no one is watching
      off = true;
    }
  }
  delay(15);
}


void doeffect()
{
   uint8_t i, r, g, b, a, c, inner, outer, ep;
  int     y1, y2, y3, y4, h;
  int8_t  y;
  
  //is anyone near ?
rangecheck();


if (duration > 100 && duration < 1000)
{
  colorWipe(pixels.Color(255, 0, 0), 50); // Red eyes, back away
}
else if(duration > 1500 && duration < 2000)
{
  colorWipe(pixels.Color(0, 255, 255), 50);
  colorWipe(pixels.Color(255, 255, 0), 50);
  colorWipe(pixels.Color(255, 0, 255), 50);
  colorWipe(pixels.Color(0, 0, 255), 50);
}
else
{
   // A steampunk aesthetic might fare better with this more subdued effect.
  // Etherial green glow with just a little animation for visual spice.
  uint8_t i, r, g, b, a, c, inner, outer, ep;


  a = (hue >> 4) & 15;
  c =  hue       & 15;
  for(i=0; i<16; i++) {
    b = (a + 1) & 15;
    iColor[i][1] = 255; // Predominantly green
    iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) +
                    pgm_read_byte(&sine[b]) *       c  ) >> 4;
    iColor[i][2] = iColor[i][0] >> 1;
    a = b;
  }
  hue -= 3;
}


  // Render current blink (if any) into brightness map
  if(blinkCounter <= blinkFrames * 2) { // In mid-blink?
    if(blinkCounter > blinkFrames) {    // Eye closing
      outer = blinkFrames * 2 - blinkCounter;
      inner = outer + 1;
    } else {                            // Eye opening
      inner = blinkCounter;
      outer = inner - 1;
    }
    y1 = upperLidTop    - (upperLidTop - upperLidBottom) * outer / blinkFrames;
    y2 = upperLidTop    - (upperLidTop - upperLidBottom) * inner / blinkFrames;
    y3 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * inner / blinkFrames;
    y4 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * outer / blinkFrames;
    for(i=0; i<16; i++) {
      y = pgm_read_byte(&yCoord[i]);
      if(y > y1) {        // Above top lid
        iBrightness[i] = 0;
      } else if(y > y2) { // Blur edge of top lid in motion
        iBrightness[i] = brightness * (y1 - y) / (y1 - y2);
      } else if(y > y3) { // In eye
        iBrightness[i] = brightness;
      } else if(y > y4) { // Blur edge of bottom lid in motion
        iBrightness[i] = brightness * (y - y4) / (y3 - y4);
      } else {            // Below bottom lid
        iBrightness[i] = 0;
      }
    }
  } else { // Not in blink -- set all 'on'
    memset(iBrightness, brightness, sizeof(iBrightness));
  }


  if(--blinkCounter == 0) { // Init next blink?
    blinkFrames  = random(4, 8);
    blinkCounter = blinkFrames * 2 + random(5, 180);
  }


  // Calculate current eye movement, possibly init next one
  if(--gazeCounter <= gazeFrames) { // Is pupil in motion?
    ep = newEyePos - eyeMotion * gazeCounter / gazeFrames; // Current pos.
    if(gazeCounter == 0) {                   // Last frame?
      eyePos      = newEyePos;               // Current position = new pos
      newEyePos   = random(16) * 16;         // New pos. (always pixel center)
      eyeMotion   = newEyePos - eyePos;      // Distance to move
      gazeFrames  = random(10, 20);          // Duration of movement
      gazeCounter = random(gazeFrames, 130); // Count to END of next movement
    }
  } else ep = eyePos; // Not moving -- fixed gaze


//  // Draw pupil -- 2 pixels wide, but sup-pixel positioning may span 3.
//  a = ep >> 4;         // First candidate
//  b = (a + 1)  & 0x0F; // 1 pixel CCW of a
//  c = (a + 2)  & 0x0F; // 2 pixels CCW of a
//  i = ep & 0x0F;       // Fraction of 'c' covered (0-15)
//  iBrightness[a] = (iBrightness[a] *       i ) >> 4;
//  iBrightness[b] = 0;
//  iBrightness[c] = (iBrightness[c] * (16 - i)) >> 4;


  // Merge iColor with iBrightness, issue to NeoPixels
  for(i=0; i<16; i++) {
    a = iBrightness[i] + 1;
    // First eye
    r = iColor[i][0];            // Initial background RGB color
    g = iColor[i][1];
    b = iColor[i][2];
    if(a) {
      r = (r * a) >> 8;          // Scale by brightness map
      g = (g * a) >> 8;
      b = (b * a) >> 8;
    }
    pixels.setPixelColor(((i + TOP_LED_FIRST) & 15),
      pgm_read_byte(&gamma8[r]), // Gamma correct and set pixel
      pgm_read_byte(&gamma8[g]),
      pgm_read_byte(&gamma8[b]));


    // Second eye uses the same colors, but reflected horizontally.
    // The same brightness map is used, but not reflected (same left/right)
    r = iColor[15 - i][0];
    g = iColor[15 - i][1];
    b = iColor[15 - i][2];
    if(a) {
      r = (r * a) >> 8;
      g = (g * a) >> 8;
      b = (b * a) >> 8;
    }
    pixels.setPixelColor(16 + ((i + TOP_LED_SECOND) & 15),
      pgm_read_byte(&gamma8[r]),
      pgm_read_byte(&gamma8[g]),
      pgm_read_byte(&gamma8[b]));
  }
  pixels.show();
}


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<pixels.numPixels(); i++) {
      pixels.setPixelColor(i, c);
      pixels.show();
      delay(wait);
  }
}






//void rainbow1(uint8_t wait) {
//  uint16_t i, j;
//
//  for(j=0; j<256; j++) {
//    for(i=0; i<pixels.numPixels(); i++) {
//      pixels.setPixelColor(i, Wheel((i+j) & 255));
//    }
//    pixels.show();
//    delay(wait);
//  }
//}


//// Slightly different, this makes the rainbow equally distributed throughout
//void rainbowCycle(uint8_t wait) {
//  uint16_t i, j;
//
//  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
//    for(i=0; i< pixels.numPixels(); i++) {
//      pixels.setPixelColor(i, Wheel(((i * 256 / pixels.numPixels()) + j) & 255));
//    }
//    pixels.show();
//    delay(wait);
//  }
//}
//// Input a value 0 to 255 to get a color value.
//// The colours are a transition r - g - b - back to r.
//uint32_t Wheel(byte WheelPos) {
//  if(WheelPos < 85) {
//   return pixels.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
//  } else if(WheelPos < 170) {
//   WheelPos -= 85;
//   return pixels.Color(255 - WheelPos * 3, 0, WheelPos * 3);
//  } else {
//   WheelPos -= 170;
//   return pixels.Color(0, WheelPos * 3, 255 - WheelPos * 3);
//  }
//}
void rangecheck()
{
/* The following trigPin/echoPin cycle is used to determine the
distance of the nearest object by bouncing soundwaves off of it. */
digitalWrite(trigPin, LOW);
//delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
//delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
/* Send a negative number to computer and Turn LED ON
to indicate "out of range" */
}

 

The making of BOB was left to my Daughter Jessica, here is her log of the process.

 

This is what we’re making, minus the digital stuff.

Cut out and iron together two layers of interfacing, one for each eye (substitute with paper if you like).

Glue to the inside of two Mason jar lid rims.

Place on a square of yellow felt. Center goggle pieces and cut out 2 grey felt goggle straps. Place.

Cut out outlines of your electronic pieces and trace onto the board with iron off marker.

To start the diaper, cut a big piece for the back, rounded at the bottom corners.

Cut out a thinner layer for the front overlap section. Glue that one on top.

Cut little safety pins out of grey fabric; 2 half circles and two long rectangles, half circles on top.

Cut safety pins in half and glue them on.

(Yes these are inaccurate, shush ;P only cut one side in half to be accurate)

Trace the outline of your baby onto a board, measure in a half-inch, round off the top and cut it out.

Fold the edge of the felt over the board (only the lower half, so you can insert electronics) and glue on.

Cut holes through board for whatever pieces require it,

(Mine needed 2 wire holes and the nose and mouth pieces)

Insert the gadgets and glue down.

Finish glueing on the eyes, the goggles, and fold over the rest of the felt edges.

 

And your done, aside from software and power, see video and above for all that stuff

 

Happy new year, Jessica Oakes

link back to primary post BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

In this episode I will demonstrate and provide all the code used to allow a browser / smartphone / tablet to adjust the colour of a light strip that is connected via an NRF24L01 2.5Ghz wireless link

 

In a previous episode I showed how to get Mosquitto server, pub and sub clients loaded into the YUN and how to use them

 

This post is extending on Benjamin Cabé's excellent demonstration and after finding all the scripts and getting the page hosted by the YUN itself I have a working demonstration that looks like the following

 

 

I can enter colours from either a subscription to the wheel ("theBreadBoard_Strip") being hosted at iot.elcipse.org or by entering colour selections directly at the YUN or the UNO via their serial terminals

 

Pay attention to case as the subscriptions are case sensitive

 

any changes via the wheel is almost instantly relayed to the UNO and subsequently displayed on the light strip,

 

The UNO is supporting a command interpreter to allow direct commands to be sent to it via any configured input mechanism (Serial or NRF at this time)

The YUN is supporting a simpler command structure at this time and simply relays the commands it receives onto the UNO via the NRF radio

 

A point to note is the YUN does not support the standard output pins for SPI, namely the MISO, MOSI and SCK lines do not exist on pins 11, 12, 13 and are only accessible via the programming header and the Infineon Shield needs stacking headers if your to add additional IO devices like a NRF24L01

 

Once all the pins where sorted out it was simply a matter of finding all the additional libraries for the web page to operate, the basic functionality required for talking to iot.elcipse.org of course comes from the PAHO js libraries but the colour wheel , Raphael and the boostrap all had to be found

 

Bootstrap · The world's most popular mobile-first and responsive front-end framework.

Raphaël—JavaScript Library

Color Wheel Demo

 

on the YUN you need to create a folder and sub folder in the root of a micro SD card "/arduino/www", once loaded into the YUN it immediately shows up at this location under the LINUX "/mnt/sda1/arduino/www" and a simpler path "/www/sd", from the home network it can be accessed as "http://arduino.local/sd/", it will automatically serve index.html


I have zipped up the SD card structure and attached for you to use


also the modified sketches for the YUN and the UNO with MQTT support and NRF24L01, there not cleaned up yet but they all work


I will be cleaning up the sketches as I add more functionality etc, I am getting close to full ram usage so it is essential before I continue much further


here is a quick video to show how it functions,





WELCOME BABY TRINKET

 

Back to the beginning BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

Great news from the Arduino Cartel

 

Senior members of the cartel, Mr and Mrs YUN have a new baby, named Trinket, she is very small and young. as a consequence she has not learned much yet but I wanted to introduce her as she will be at the party so with help from several minions, we will endeavour to train educate her as best we can before the party,

 

She has already learned how to wow the parents with her Big colourful eyes so who knows what else she will learn between now and the party

 

We have not been privy to a full picture of Trinket yet but have seen fragments

 

This is what we have seen of Trinket so far and here is where she was created, oh er I mean born : https://learn.adafruit.com/introducing-trinket/introduction

 

 

 

 

 

 

 

 

 

 

 

It was a perfect creation, with those big colourful eyes


NeoPixel Ring - 16 x WS2812 5050 RGB LED with Integrated Drivers

NeoPixel Ring - 16 x WS2812 5050 RGB LED with Integrated Drivers

 

Not sure about the nostrils though...ugghhh

P1010320.JPG

 

and parents really should think twice about those soother things

189-03.jpg

 

As a further treat I was able to capture some footage of her asleep but we woke here and we had to leave before we got a good look, here is what we captured

 

Here is the current sketch, evolved from the one she came with as she has learned new tricks

 

Trinket is based on an ATTINY85 so IO is limited and so every pin counts

 

I will be using one for the NEOPIXEL rings, one for the PIR and two for the range sensor, that leaves me one pin spare... oh what to do with it , maybe a voice ?????


MQTT Server on the Arduino YUN

 

Back to the beginning BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights


In this episode leading up to the final party of the year we look at running the MQTT Server directly on the YUN, there are numerous posts where this is running on a VM on a PC or on another more capable device but truth be known, it will run perfectly well on the YUN OpenWRT  Linux kernel directly, With the help from Mrs YUN,  ill show you how


A video if you prefer (Oh, and I kept it under a half hour )

 

 

Or the text version for those so inclined to read , you know who you are

 

First thing is to update the Yun, use a wireless device or connect via the Ethernet port

(Wireless you look for the YUN SSID and connect, no code needed, then browse to "arduino")

(Ethernet, browse to the ip address or connect to arduino.local )

log in with the default password "arduino", the following screen is after the upgrade (Sorry, the video contains the original )

click configure and fill in for your local network

Set your time zone (Apparently Canada is part of America... who knew, so to find Toronto you need to select "America, Toronto), you don't need to change the password but do so if you wish

If your planning on using the REST interface and don't want it to be secure (No Password prompt when you try to access the rest interface), then also check "OPEN"

Then click on "Configure & restart"

 

I had to repeat this a few times before it stuck (Or I finally got the WIFI password right, one or the other )

 

anyway, once it is connecting to the local intranet (Home network), you should be able to connect using the url "HTTP://arduino.local", if this does not work, you may need to look at your router so see the IP address assigned to it and connect directly via the IP address "HTTP://192.168.nnn.nnn" or what ever your network is configured for. once you connect you will see a screen similar to that shown above, you may have different IP address of course.

 

After setting up the YUN via the WEB browser to configure it to connect to your local internet connection via WIFI or use the Ethernet port (Where's the fun in that)

 

Given your successful you should be able to SSH into the Linux side of the board. I use a program called PUTTY (Down load from PuTTY: a free telnet/ssh client  ), the screen below show the start screen and how I configure it for my instance of a YUN. Saving the setting makes life so much easier later on

on connection you will be presented with a logon prompt, enter "root" for the logon name followed by "arduino" for the password

 

you should have a screen like the one below but without the mosquitto (MQTT) stuff at the bottom, note the date of the core version

BusyBox v1.19.4 (2014-11-13 19:03:47 CET), if yours is not at this level or newer, you may need to upgrade, I have two YUN's and one would work without upgrade, one would not, neither where at this date revision but all had the same version (v1.19.4) so I guess they don't update the version numbers for over a years worth of updates.so if things don't work and your not at this version, upgrade, it is very painless and I will have a video below (To Follow) to show how easy it is.

 

So once were here we can proceed to install the required software, this is available at the Mosquitto.org website "Mosquitto on OpenWrt | Mosquitto" simply follow the instructions

 

opkg update
opkg install mosquitto mosquitto-client libmosquitto



and your ready to roll, just type "mosquitto" at the command prompt and your broker is ready and running

here is the screen show of those steps

using the samples provided on the mosquitto MQTT site, it is easy to test the servers operation (See here: Documentation | Mosquitto )

once subscribers and publishers start to use the server, it will print messages on the console as shown below

I set up a raspberry pi with MQTT client and published a few events to the YUN as shown here, it also had a second console subscribed to only the humidity topic (Was on temperature to start with)

The YUN console subscribed to a wild card topic using "oakesclan/#" and received every publication as shown (# is a wild card for MQTT topics)

So, there you have it, the Arduino YUN does not need a separate server to support MQTT, it is more than able to host the server itself and have numerous consoles running at the same time, in the next post I will be getting the Arduino side of the YUN to subscribe to the Linux side MQTT server and have it react to commands sent to the MQTT broker, at a later stage I will also try to configure the server to bridge to the Eclipse sandbox, extending the reach of the party.


Now Mrs YUN is ready to relay messages between all the guest who want to talk and those who will listen, now we need radios for the none network connected guests.

Party Message Board

 

Back to the beginning BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

I hope your all finding the information useful so far, this is proving to be a fun packed challenge

 

For today I have chosen to test out the 16*32 panels I bought from Adafruit, they arrived today (yaaa, so many presents already ), these are not really meant for UNOs and the like, there really for massive street signs and ideally driven by powerful FPGA based systems but the great folks at adafruit have done a superb job of writing some libraries to allow them to be driven by even an UNO or a Mega with plenty of room to spare for other code, these displays have to be driven as a matrix actively by the UNO (There not neo pixels) so a fair percentage of cpu time needs to be used to scan the images onto the panel

 

This is what you get:

P1010331.jpg

 

You can find all the code and wiring details here: http://www.adafruit.com/product/420 and believe me, these things are awesome, wire them up as instructed, apply power and a test sketch and it just works, It was even working before I connected the correct supply to the panel (Albeit a bit dimly)

 

My plan it to have Mr UNO or Mrs Yun drive this and possibly another to display web messages of cheer from a web site or twitter feed, may need moderation though or a menu of messages to select from, but for now I wanted to test how easy it is to use and send a holiday greeting to my companion competitors and eager followers

 

so here is the video of this working, and I have to say, these things are AWESOME



WARNING:

While I'm on the subject of testing, I did discover an annoying feature of the Infineon RGB Board (Or more specifically the Yun and its compatibility with Shields) , It wont fit on the Yun without using a set of Stacking headers (The kind you get if your making your own shields)

 

Here is what happens without

P1010332.jpg

As you can see, the board barely makes contact with the sockets and it is already hitting the top of the Ethernet port, nothing that a set of stacking headers cant fix, but of course you need the headers, also available from Adafruit

 

Now it works (The stacking header pins are long, they are well and truly inserted)

P1010334.jpg

 

OK, that's it for this update, with luck more goodies will arrive tomorrow and I will share more details of how to connect up and where to get libraries

Filter Blog

By date: By tag: