Arduino and Omni PRO II via serial - first working code.

tigers

Active Member
dementeddigital said:
What else do you have in there?  Pics?  (Curiosity mixed with jealousy!)
 
I'm following this thread with much interest, as I'm planning on my second OPII install.  (New house)
 
If you guys want to do any custom electronic hardware, let me know.  We can collaborate on a design.  I don't mind doing the schematic and board layout, and I know of a place where we can get inexpensive boards fabricated.
That would be cool. At the moment I am working on a programmable remote thermostat, controlled via ethernet connection. I'm at a decently working stage with both software and hardware but the big problem is shrinking it in some kind of box that can be placed on the wall. Unfortunately I'm in Europe...
At the moment I resolved by putting only the sensor in the room, and the thermostat is out of the way in an ordinary electric plastic box.
 

pete_c

Guru
Yeah I would be interested in something like this. 
 
You cannot really do much inside of the stock OmniPro can that comes with the OP2.  That said 2nd HAI OPII takes advantage of the small footprint in a small closet with another Leviton Can doing other stuff but a much simplier installation.
 
The Leviton HAI Email Board is a bandaid and it doesn't fix the NIC port issue on the OPII panel and its too big.
 
leviton 20A30-1.jpgmicrorouter.jpg
 
Personally here it was all about the footprint inside of the panel and fixing an inherent problem with the OPII old NIC port.
 
The tiny firewall / router fixed my issue relating to the old OmniPro II promiscuous NIC which actually makes the OPII disfunctional.
 
LevitonOP2.jpgleviton 20A30-1- B.jpg
 
This sort of RPi based design and board are too big and expensive at over $200. 
 
RPi2-base.jpg
 
Might as well go to an Intel Baytrail based tiny motherboard which is the same size as the above board.
 
Tiger's stuff is based on an Arduino (very inexpensive) and my micro router cost $20 (unmodified).
 
Personally I would pay up to $150 USD for a combo multiNIC, firewall router, email board, web server HAI OPII base very simple management with RTC clock built in and a little management interface as icing on the cake.
 

JonW

Senior Member
I'm a little late to this thread, but if you want ethernet connectivity to the OPII in a micro, you can easily run the HAI SDK examples on a Raspberry Pi by simply loading the Mono package on the Pi. I've recently developed a few programs in Visual Studio that I moved to the Pi by using Mono and I'm blown away by the performance. After having such great results with some of my other apps, I ended up tweaking my HAI control app and tested it on the Rpi with great success. I have dedicated Windows servers running in the house, so I likely won't be moving my HAI stuff to Rpi permanently, but it is a good option for Windows developers who want their app to run on a micro.
 

pete_c

Guru
Very nice John!
 
Would you post some screen shots of your control application running on the RPi2?
 
Here currently running / testing the Homeseer OmniPro plugin on an RPi2. 
 
The plugin can run by itself on the RPi2 remotely connecting to the panel and Homeseer or on the Homeseer box (RPi2 or Ubuntu server)..
 
It does well but is not finished at this time.
 

JonW

Senior Member
Attached are a few pics o a Win32 app running on Rpi. I don't use this for daily control, so that's why it's more utilitarian looking than pretty graphics. I have a version that runs as a service on a server that logs all activity to a SQL server.  Sorry for the size of the pics - a bit hurried and didn't resize them.
 
HAI_Rpi_Setup.png

 
HAI_Rpi_Control.png

 
HAI_Rpi_Log.png
 

pete_c

Guru
Very nice John.  What program do you utilize for daily control?
 
Yes here my Homeseer touch screens get busy as I look more at function with them rather than graphics.
 

JonW

Senior Member
pete_c said:
Very nice John.  What program do you utilize for daily control?
 
Yes here my Homeseer touch screens get busy as I look more at function with them rather than graphics.
I mostly use the [email protected] app on my iPhones.  I have older/spare i5's around the house.
 
Now that I know how well Visual Studio apps run with Mono on the Rpi, I may make a touchscreen app to run on a Rpi/mini touchscreen combo.
 

pete_c

Guru
Here I cannot get a good graphical interface (very slow) running in Linux Mono relating to Homeseer touch. 
 
I have tried many times.
 
It is said (maybe it's a rumor) that the RPi / RPi2 was invented to run XBMC / KODI. 
 
That said the graphical XBMC/KODI in pure Linux OS (sans Mono) on the RPi2 works and is very fast.
 
Running HSTouch / Mono on the RPi2 is very slow and mostly non touch responsive.
 
Using same Intel Atom based tablet running in XP / W7 embedded Homeseer touch  works fine and is fast. 
 
While I have Omnitouch screens; HAI Omnitouch Pro software runs fine on my Atom tabletop touchscreens.
 

JonW

Senior Member
Pete - Sounds to me like the sluggishness is in HSTouch, not the Pi or Mono.
 
I started testing my apps on the Rpi because I have a brewery control system touchscreen interface that I wrote and want people to be able to run it on a simple Rpi/screen combo without needing a PC.  As I said previously, I've been really impressed with the performance, so I will likely end up doing an HAI touchscreen interface also.
 
The architecture of the way my brewery touchscreen works is such that when you touch a button to activate a device or process, the command is sent to the brewery controller and a reply must be received to acknowledge the command has been performed before the screen buttons change.  This is done in milliseconds and gives the impression that the button changed just by virtue of you pressing it - there is very little lag.  The big benefit to doing it that way is that all screens used for controlling the brewery change simultaneously and always show the same status.
 

pete_c

Guru
Pete - Sounds to me like the sluggishness is in HSTouch, not the Pi or Mono.
 
Yup right-o.
 
There is a constant non stop chat chat from the mothership which appears to take precendence on the CPU/GPU utilization many times appearing to cache the touch pieces such that they can become unresponsive. 
 
It is my fault too for trying to fit as many variables or button statuses  & scripting at the button level. The variables can come from the mothership or a one liner script call at the button.  (I call a button whatever it is I populate a screen with).,
 
This is on XPe / CE / W7e or W10 on an Atom, Core duo or iSeries PC uses as a touchscreen.
 
Not too many Homeseer folks have ever utilized the mono HSTouch for Linux such that it's never been tweaked or  upgraded for many many years.  Primarily most of the resources have gone in to tweaking the Android / iOS versions of HSTouch.  The very first version though was Microsoft CE and today it still works OK.  Similiar a bit to the HAI Omnitouch Pro being able to run fine on CE, XP, XPe, W7e and W10.  (except for some gotchas),
 
because I have a brewery control system touchscreen interface
 
Sounds like the ultimate automation. 
 
A few years back got to get a granular look (the tour) at Bell's Brewery (went to a wedding shower, baby shower et al that happened there - for a bit we lived there almost - food and entertainment was very nice) set up in Kalamazoo, Michigan. 
 
There was no automation from what I could see and they did have a process of disassembing and cleaning some very old looking valves and such using much analog stuff.  (post it notes on the containers with cryptic cataloged descriptions of the brews. 
 

cestor

Active Member
Sorry if this is a stupid question - is there a quick way to copy and paste the arduino code sample without the line number?
 

pete_c

Guru
Yes.
 
Playing a bit right now.  Tiger is helping me a bit with the following that will use Lua (which is very similiar to C).
 
I am playing with a miniature microrouter (GliNet) with more memory than the TP-Link microrouter.  It is half the size of the TP-Link.  I am using OpenWRT, Lua and LuCi.
 
openwrt.jpg
 
Here is a link to LuaEdit.
 
luaedit.jpg
 
CT-GLiNet.jpg
 
This is just a copy of what tiger posted above and paste from LuaEdit to the forum post.
Code:
//Define the arrays that will contain the data
#define DATABUFFERSIZE 255
const byte headerByte = 0x5A; // or '!', or whatever your start character is

byte byteRead;
byte HAI_send[DATABUFFERSIZE];
byte HAI_receive[DATABUFFERSIZE];

const byte HAI_OK[] = { 0x5A, 0x01, 0x05, 0xC1, 0x93}; // Standard acknowledge OK answer
const byte HAI_KO[] = { 0x5A, 0x01, 0x05, 0xC1, 0x92}; // Standard acknowledge but NOT OK answer

const byte PASSWORD[] = { 0, 0, 0, 0 }; //the master code used to login with the HAI console
// PLEASE NOTE: THIS WILL BE SENT IN PERFECTLY CLEAR MODE (NO ENCRYPTION) OVER THE SERIAL PORT
// THIS IS HOW HAI DOES IT, THE SERIAL PROTOCOL ISN'T ENCRYPTED SINCE IT REQUIRES PHYSICAL ACCESS TO
// THE PANEL

//==============CRC ROUTINE===========
//From HAI docs:
/*  starting with the message length byte, call Update_CRC for each byte
of the message passing the message byte in Data.  The low byte of CRC will contain
the low byte of the CRC-16 remainder and should be sent first.  The high byte of
CRC will contain the high byte of the CRC-16 remainder and should be sent last. */
//----------------------------------------------------------------------

//DAVIDE may 12 2014:
//I rewrote the routine from the HAI docs translating form the turbo Pascal version,
//which was easier for me than the C version that used pointers and did not run on Arduino
//Someone who knows how to program should modify it and maybe write a CRC append routine
 
unsigned int crc16_update(unsigned int crc, byte x)
  {
    static int const Poly = 0xA001;    // CRC-16 polynomial
    int i;
    bool flag;
 
    crc ^= x;
    for (i=0; i<8; i++)
    {
      flag = (crc & 1) != 0;
      crc = (crc >> 1);
      if (flag)
        crc ^= Poly;
     }//END for     
   return crc;
   }//END crc16_update()

/*
//calculates crc for an entire output message, putting the result in the 2 bytes after message ending
unsigned int messageOutCrc (){ (//no args because length is in the 2nd place of the array
   unsigned int crc = 0, i;
   unsigned byte totalLength; //total length of the message in the array, including header, length but excluding the 2 crc bytes
   
   totalLength = HAI_send[2] + 2 //+2 is for accounting the header and length bytes that are not computed in the length byte
   for (i = 2; i <= totalLength; i++)  //i=2 because the CRC is WITHOUT message header HAI_send [2] is message length (excluding header and length) so I add +2
       crc = crc16_update(crc, HAI_send[i]);
   HAI_send[totalLength + 1] = lowByte (crc);//penultimate byte of the message CRC1
   HAI_send[totalLength + 2] = highByte(crc);//last byte of the message CRC2
}//END messageOutCrc*/

//LOGIN - composes the login string starting from the master code
void HAI_login (){
 
  HAI_send[1] = 0x5A; //header
  HAI_send[2] = 0x05; //message length
  HAI_send[3] = 0x20; //it's a login
  HAI_send[4] = PASSWORD[0]; //first digit of the code
  HAI_send[5] = PASSWORD[1];
  HAI_send[6] = PASSWORD[2];
  HAI_send[7] = PASSWORD[3];
 
  unsigned int crc = 0, i;
        for (i = 2; i <= 7; i++)  //i=2 because the CRC is WITHOUT message header
            crc = crc16_update(crc, HAI_send[i]);

  //calculate high and low byte of the CRC
  //byte low_byte = 0xff & crc;
  //byte high_byte = crc >> 8;

  HAI_send[8] = lowByte (crc);
  HAI_send[9] = highByte(crc);

}//END HAI_login
   

/*The COMMAND message is used to send an immediate control command to the HAI controller.  Commands are
provided  to  control  lights,  appliances,  temperatures,  security,  and  messaging.    Each  command  follows  the  same
format: a single byte command, followed by a single byte parameter, and then a two byte secondary parameter.  The
command message is formatted as follows:
 
  Start character   0x5A
  Message length    0x05
  Message type      0x0F
  Data 1            Command
  Data 2            Parameter 1
  Data 3            High byte of parameter 2
  Data 4            Low byte of parameter 2
  CRC 1             varies
  CRC 2             varies */

//compose the array for a set flag command (command 0x0C = set flag P2 to value P1)
void SetFlagTo (int flagNumber, byte level){
  //using base 1 for the array for human readability
  //the first part of the set flag command are fixed values:
  HAI_send[1] = 0x5A; //header
  HAI_send[2] = 0x05; //message length
  HAI_send[3] = 0x0F; //it's a command
  HAI_send[4] = 0x0C; //it's a set flag command: 0x0B to increment counter - 0x0C to decrement counter
  HAI_send[5] = level; //the level to set to
 
  // then we must calculate high and low byte of the Flag number
  //byte low_byte = 0xff & flagNumber;
  //byte high_byte = flagNumber >> 8;
  //...and append to the previous part
  HAI_send[6] = highByte(flagNumber);
  HAI_send[7] = lowByte (flagNumber);
 
  //now the CRC
 
  //this should become a function unsigned int messageOutCrc (byte length) - length could be determined from the 2nd element
  //no array passed to the function (don't know how to) - data will be get and put in the HAI_send global array
  unsigned int crc = 0, i;

        for (i = 2; i <= 7; i++)  //i=2 because the CRC is WITHOUT message header
            crc = crc16_update(crc, HAI_send[i]);

  //calculate high and low byte of the CRC
  byte low_byte = 0xff & crc;
  byte high_byte = crc >> 8;

  HAI_send[8] = low_byte;// (flagNumber);
  HAI_send[9] = high_byte;// (flagNumber);
 
}//END SetFlagTo

void SetUnitOn (int unitNumber, byte time){ //time is 0 = permanent OR 1-99 seconds OR 101-199 for n-100 minutes OR 201-218 for n-200 hours

  //TBD command 0x01
 
}

void SetUnitOff (int unitNumber, byte time){ //time is 0 = permanent OR 1-99 seconds OR 101-199 for n-100 minutes OR 201-218 for n-200 hours

  //TBD - command 0x00
 
}

void executeButton (int buttonNumber){

  //TBD - command 0x07
 
}

void getTemperature (int Zone){

  //TBD - command
 
}

//convert Omni temperature to C
float omniToC (byte omniT) {
  //OmniT is just 0 when -40 °C and every OmniT step is 0.5 °C
  //omnitoF in a little more complicated, I think the best thing to do is convert the °C value to °F
  return (omniT*0.5 - 40);
 
}//END OmnitoC


//the serial array function comes from http://jhaskellsblog.blogspot.it/2011/05/serial-comm-fundamentals-on-arduino.html?m=1
//with modifications since the HAI protocol doesn't have end byte but a length instead, also it doesn't read strings or chars
//and doesn't need NULL termination
boolean getSerialArray(){
    static byte dataBufferIndex = 0;
    byte messageSize=DATABUFFERSIZE; //length of the message, at the beginning it can be the maximum value
    boolean storeVal; //flag to define if the incomingbyte have to be put in the array
    
    while(Serial1.available()>0){
        Serial.println("listening...");//DEBUG
        byte incomingbyte = Serial1.read();
        if(incomingbyte==headerByte){
            Serial.println("Reading HAI message... ");//DEBUG
            dataBufferIndex = 1;  //Initialize our dataBufferIndex variable
            storeVal = true;
            messageSize=2;//so i read at least 2 bytes
        }//END if
        
        if(storeVal){
            //Let's check our index here, and abort if we're outside our buffer size
            //We use our define here so our buffer size can be easily modified
            if(dataBufferIndex == 2){
                //this is the length of the message - I put it in a variable
                messageSize = incomingbyte + 2 +2; //adding the 2 CRC values and Header and length - this is the final index
            }//END if databufferIndex==2
            if(dataBufferIndex == DATABUFFERSIZE){
                //Oops, our index is pointing to an array element outside our buffer.
                dataBufferIndex = 0;
                break;
            }
            else{
                HAI_receive[dataBufferIndex++] = incomingbyte;
                //dataBuffer[dataBufferIndex] = 0; //null terminate the C string
        if (dataBufferIndex==messageSize){//We have read all the data
          return true;
            }
            }//END else
        }
        else{
        }
    }
   
    //We've read in all the available Serial data, and don't have a valid string yet, so return false
    return false;
} // END getSerialArray


//======MAIN PROGRAM==================================
void setup() {                
// Turn the Serial Protocol ON
  Serial.begin(9600); //for debug
  Serial1.begin(9600); //for communications with HAI panel
 
  while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only
  }

  delay(2000);

   

}//END Setup()

void loop() {

  if (Serial.available()){
    char inChar = (char)Serial.read();
      if (inChar == 'f') {
        
          SetFlagTo (417,100); //set flag 417 to X value
          //setflag is 9 byte long including CRC
           Serial.print("Sent to HAI:");
           for (int i = 1; i <= 9; i++) {
             Serial1.write(HAI_send[i]); //to HAI
             
             Serial.print(HAI_send[i],HEX);//for debugging - comment out in final release
             Serial.write (" ");
           }//END for
           Serial.println();
           
           //For debug the content is sent on Serial
           Serial.print("received:");
           for (int i=1;i<=9;i++){
             Serial.print (HAI_receive[i],HEX);
             Serial.print (" ");   
           }//END for
           Serial.println();
           
      }//END IF inchar == 'f'
      if (inChar == 'l') {
       //TEST SetFlag Routine
         HAI_login(); //login to HAI console sets up the HAI_send with the message
      
      // NOTE: the send function must be generalised void SendToHAI (byte lenghtOfMessage) - could be omitted and derived from 2nd element of the array
      // I don't know how to pass an array as a function argument in C (pointers?) but for the purpose
      // the global HAI_send and HAI_receive arrays are just fine.
         //send the message
         //login is 9 byte long including CRC
         for (int i = 1; i <= 9; i++) {
            Serial1.write(HAI_send[i]); //to HAI
           
            Serial.print(HAI_send[i],HEX); //for debugging - comment out in final release
            Serial.write (" ");
         }//END FOR int
         
         Serial.println();
      }//END if intchar='l'
 
      
  }//IF Serial.available  
 
 
  /*  
//TEST routine that echoes the Serial input to the Serial1 (connected to HAI with a TTL to RS232 adapter)
  //  check if data has been sent from the computer:
  if (Serial.available()) {
    // read the most recent byte
    byteRead = Serial.read();
    //ECHO the value that was read, back to the serial port.
    Serial1.write(byteRead);
  }
 
//TEST routine that echoes the Serial1 input from HAI to the Serial port of Arduino for debbugging
  if (Serial1.available()) {
    // read the most recent byte
    byteRead = Serial1.read();
    //ECHO the value that was read, back to the serial port.
    Serial.write(byteRead);
  }//END IF  */
 
 // SERIAL READ
 
  if (getSerialArray()){ //the function places valid series of bytes in the HAI_receive[] array
      
    //For debug the content is sent on Serial
    for (int i=1;i<=9;i++){
    Serial.print (HAI_receive[i],HEX);
    Serial.print (" ");

    }//END for
    
    Serial.println();
    
    //CRC CHECKING GOES HERE
    
    //HAI_receive PARSING GOES HERE
 
  }//END if getSerialArray
 
   
}//END loop()
 

pete_c

Guru
Welcome to the Cocoontech forum enry86cami!
 
 
Personally here thinking that will work. 
 
Any means of a serial connection will work.  You only need to utilize 3 wires: RX, TX and Ground.
 
You can test out communications with serial port configuring the port to Pro-Link or Omni-Link.  Try the simplest communications protocal first using:
 
post-11125-0-48662600-1399230090.jpg

 
Setting the port to 9600 8N1.
 
Write a quickie on PCA automation couple of lines script.  IE: press a button and send a message out to OPII serial port XX.  Test your cable out with a terminal program running on any PC.  It will see the serial chit chat just fine.
 

tigers

Active Member
Yes, that interface is OK, and also the pinout and suggestions from pete_c.
If you use arduino the terminal program can be the arduino serial monitor. The "press a button" test is fine but you must set the serial port accordingly in pc access first. If you wanna communicate from and to like in my sketch you must use the HAI link protocol, if you just wanna do some test from OPII to pc or arduino then omni pro protocol is the way to go.
Please remember that my code may have some problem if your password contains zeroes. Better change it to be site while testing.
 
Top