Posts Tagged ‘PLC’

So I have been working hard over the last few month trying to consolidate many pieces of what I hope to be the decorations master piece for 2010.

Here is how it started.  For 2009 I had already created a simple programs that would randomly play small 5-10 second sequences such as fading on / fading off, lighting bolts etc. And even in Halloween/Christmas starting I start projecting some images and clips on the window using my laptop and a projector. But wouldn’t it be nice to have it all sync together?  This is where this ‘project’ came up.

For starters I considered dropping these boxes and going with the Light-o-rama product.   Which I am sure you have seen 1000 times before and that same Transiberian Orchestra song!  But after downloading the demo software I found there was no way I could insert code or run a program before or after.   Don’t get me wrong its a excellent product and insteon devices will NEVER match the speed those device can achieve!   But another limitation ‘I’ didn’t like was that its all in central controllers. With the lamplincs I can and have had devices inside the home and some outside at the same time, also if one device dies you replace it and your done, here if you controller dies you are down 16 ‘channels’ .  BUT Downside for me is each device needs to be  programmed individually but once its set your ready to go!.  Another big plus for me was that I could use existing Insteon devices over and over and even mix with the ones in the home.  For example in Halloween I would kill the kitchen lights inside for the lighting bolts outside.   So in true ‘me’ spirit I decided to stick with Insteon and do something different!

Here are some of the LampLincs I’ve picked up over 2009/2010.  Each are identified by unique #

The Show Manager

So “Show Manager” is basically the conductor that start and stop these individual programs.  Here is a high level chart of what it consist of.

For example the ‘Show Manager’ will start and stop the ‘Randomizer’, ‘Sequencer’ as well as accept input from the internet.  Like in 2009 I will provide a button from our community website/ internet users to ‘bump’ the decorations. 🙂  Try that Lightorama.

The program is a simple program that will start and stop programs using VB program looking as the processes in memory.

The “Sequencer” Program (New for 2010)

Different from 2009 is the ‘Sequencer’ program which is what allows me to sync video/audio to commands to the devices.  The screen is very simple and clear.  You have a time line which is broken down in .25 seconds with the devices down the left.  Each color is a different command sent via the serial interface.

Closeup of the Time line board.

Close up of the commands screen

Synchronizing the video between the two computers was a ‘TASK’ .   I had to get down to the milliseconds so the video would sync correctly,

For this I had to use VB 2008/2010 Windows presentation format (WPF) in the remote laptop since you can change the rate of play of the video. I never found a right way to do this in VB 2008 or less. So the main sequencer would send a heartbeat to the laptop everysecond with its time sync so the player could go slower or faster.

The way I put them to talk is a previous entry here, how to Communicate using ports / TCP.   HERE

To be continued….

Hi, so I know ive been disconnected for a while.  But always trying to provide some goodies.

One of the cool things of the PLC is that if you know serial commands you can actually talk to it bypassing the SDM software.  My reason being that X10 motion sensors are cheeper than the Insteon and smaller which I can hide in different places but I would run in to the problem of the x10 signals not making it back to my main computer.  So what If you can have something on another computer which can transalate it to Insteon ?:)

So what I was right on the back of the PLC I have a transceiver and use the PLC with this small code to convert it to Insteon.  This way I basically have a x10 receiver on the other leg of my home.

So below is a small little program I use to  ‘convert’ X10 signals to a Insteon signal.  In my case the PLC will sending a ON  or OFF command to the PLM and depending the rate is the house code for example (B5,B6).   For the example im using VB 2005.  2008 and 2010 will work fine as well.  Note that i am bypassing entirely the SDM software.  if you don’t call it in your code it wont load, but you do have the port locked and isn’t sharable  🙂

A very good starting point is this site and I basically started from here http://www.madreporite.com/insteon/insteon.html which will show you how read bytes, which is how the plc will respond as well.

Basically the PLC talks at 4800,8,N,1.  The program consist of a simple form with  just one button to exit.


Option Strict Off
Option Explicit On
Imports VB = Microsoft.VisualBasic
Imports System.IO
Imports System.IO.Ports
Imports System.Net

Public Class Form1
 Public WithEvents PLC As New IO.Ports.SerialPort
 Public X10_House_Code As String
 Public X10_House_VALUE As Integer
 Public X10_Command As String
 Public PLC_Queue As String
 Public handler As New mySerialDelegate(AddressOf Process_Queue)  ' Once we read the data process it in a separate thread.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 '------ OPEN PLC SERIAL CONNECTION SETUP PLC AND LEAVE READY - 
 PLC.PortName = "COM1"
 PLC.BaudRate = 4800
 PLC.DataBits = 8
 PLC.Parity = Parity.None
 PLC.StopBits = StopBits.One
 If PLC.IsOpen = False Then PLC.Open()

End Sub

 '---- THIS IS THE EVENT THAT WILL FIRE EACH TIME DATA IS RECEIVED BASICALLY WE CAPTURE ALL THE DATA AND
 '---- CALL THE OTHER THEAD TO CONVERT IT.
 Private Sub PLC_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles PLC.DataReceived
 Dim A, Bytes_to_read As Integer
 Dim rcvBuf(4096) As Byte
 Bytes_to_read = PLC.BytesToRead
 Do While PLC.BytesToRead > 0
 PLC.Read(rcvBuf, 0, rcvBuf.Length)
 For A = 0 To Bytes_to_read - 1
 PLC_Queue = PLC_Queue + Hex(rcvBuf(A)).PadLeft(2, "0") + " "
 Next
 Bytes_to_read = PLC.BytesToRead

 Loop

 Me.BeginInvoke(handler)
 End Sub

 Public Delegate Sub mySerialDelegate()
 Public Sub Process_Queue()

 'CONVERT STEAM TO X10 HOUSE CODES and the VALUE THAT WILL BE PASS TO THE OTHER DEVICE
 ' SO WHEN IT SEEN B2 IT WILL SEND TO THE OTHER SIDE A VALUE OF 18 ON THE RATE OR 'ON' VALUE
 ' Im only converting the B Code nothing else. 

 If PLC_Queue.Contains("02 4A 00 EE ") Then X10_House_Code = "B2" : X10_House_VALUE = 18
 If PLC_Queue.Contains("02 4A 00 E2 ") Then X10_House_Code = "B3" : X10_House_VALUE = 19
 If PLC_Queue.Contains("02 4A 00 EA ") Then X10_House_Code = "B4" : X10_House_VALUE = 20
 If PLC_Queue.Contains("02 4A 00 E1 ") Then X10_House_Code = "B5" : X10_House_VALUE = 21
 If PLC_Queue.Contains("02 4A 00 E9 ") Then X10_House_Code = "B6" : X10_House_VALUE = 22
 If PLC_Queue.Contains("02 4A 00 E5 ") Then X10_House_Code = "B7" : X10_House_VALUE = 23
 If PLC_Queue.Contains("02 4A 00 E4 ") Then X10_House_Code = "B8" : X10_House_VALUE = 24
 If PLC_Queue.Contains("02 4A 00 E7 ") Then X10_House_Code = "B9" : X10_House_VALUE = 25
 If PLC_Queue.Contains("02 4A 00 EF ") Then X10_House_Code = "B10" : X10_House_VALUE = 26
 If PLC_Queue.Contains("02 4A 00 E3 ") Then X10_House_Code = "B11" : X10_House_VALUE = 27
 If PLC_Queue.Contains("02 4A 00 EB ") Then X10_House_Code = "B12" : X10_House_VALUE = 28
 If PLC_Queue.Contains("02 4A 00 E0 ") Then X10_House_Code = "B13" : X10_House_VALUE = 30
 If PLC_Queue.Contains("02 4A 00 E8 ") Then X10_House_Code = "B14" : X10_House_VALUE = 31
 If PLC_Queue.Contains("02 4A 00 E4 ") Then X10_House_Code = "B15" : X10_House_VALUE = 32
 If PLC_Queue.Contains("02 4A 00 EC ") Then X10_House_Code = "B16" : X10_House_VALUE = 32

 '- ON OR OFF
 If PLC_Queue.Contains("02 4A 01 E2 ") Then X10_Command = "ON" : Send_Bytes(X10_House_VALUE, True) : Debug.Print(X10_House_Code) : X10_House_Code = "" : X10_Command = ""
 If PLC_Queue.Contains("02 4A 01 E3 ") Then X10_Command = "OFF" : Send_Bytes(X10_House_VALUE, False) : Debug.Print(X10_House_Code) : X10_House_Code = "" : X10_Command = ""

 Debug.Print(PLC_Queue)

 ' Clear and start again
 PLC_Queue = ""
 End Sub

Public Function Send_Bytes(ByVal value As Integer, ByVal State As Boolean) As Boolean
 Dim RECEIVER() As String = Split("0D.FE.9E", ".")  '-- THIS CONTAINS WHO WE ARE SENDING THE MESSAGE TO CHANGE AS NECESSARY
 '-- MAGIC CODE TO SEND TO PLC (I'LL EXPLAIN THEM LATER)
 Dim xmtbuf() As Byte = {&H2, &H40, &H1, &HA1, &H0, &H9, &HFD, &HE4, &H0, &H0, &H0, &HD, &HB, &H44, &H5, &H11, &H1}

 '-- HERE WE WILL REPLACE THE BYTES ABOVE IN BOLD TO WANT TO SEND TO,
 xmtbuf(11) = System.Convert.ToInt32(RECEIVER(0), 16)
 xmtbuf(12) = System.Convert.ToInt32(RECEIVER(1), 16)
 xmtbuf(13) = System.Convert.ToInt32(RECEIVER(2), 16)

 '- DEPENDING ON THE DEVICE BEING ON OR OFF WE SWAP ONE OF THE BYTES
 If State = True Then xmtbuf(15) = 17 Else xmtbuf(15) = 19 ' If on then push 17 if off push 19

 '--- HERE WE INSERT THE VALUE / X10 HOUSE CODE WE HAVE PREDIFINED 
 xmtbuf(16) = value

 '--- CALL OUR LITTLE FUNCTION TO WRITE THE BYTES TO THE SERIAL PORT
 PLC_Write(xmtbuf)

 '--- SETUP SOME MORE BYTES (THIS DOENST CHANGE) AND WRITE THEM, THIS TELLS THE PLC TO PROCESS THE BYTES WE SENT
 '--- BEFORE
 Dim xmtBuf2() As Byte = {&H2, &H46, &H1, &H42, &H10, &H9F}
 PLC_Write(xmtBuf2)
 End Function

 '--- THIS FUNCTION BASICALY WRITES ALL BYTES TO THE SERIAL PORT WE HAVE PREVIOUSLY DEFINED
 Public Function PLC_Write(ByVal XmtBuf As Object) As Boolean
 Try
 PLC.Write(XmtBuf, 0, XmtBuf.Length)
 Catch
 Debug.Print("COULDNT SEND DATA CHECK PORT")
 End Try

 End Function

 '--- SIMPLE BUTTON ON OUR FORM TO EXIT THE PROGRAM
 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 End
 End Sub
End Class

We’ll after receiving back some of my hard earned money thru 2008. I shelved out the $159 for the Insteon T1700 thermostat.
It can be found here.

The device is quite small, which is fine and thinner that my orginary Honeywell one which was a real plus.  To install was also very simple.
And technical support was awesome!!!  Who expects to call a company and receive a live person and be able to troubleshoot on the phone in less that 3 min.  And to top it off the rep even called me back since he had to leave. At the end it was a simple dip switch due to my model.  So if after you install it and when you turn on cool and heat comes out and vice-versa, just turn on dip switch two and your set!  Thats Again Mike from Venstar!!!!


The only thing would be the ‘light’ on the side of the Insteon module.  so in dark areas it does stand out.
Like mentioned above the device is very small and the insteon module even smaller.
For example check out the image in comparison to my hand

Setting Mode, Getting Temperature of Thermostat

Ok, enough Pictures and talk, lets see how to control this device.

First forget about sending ON/OFF commands, for me they didnt work, nor did they do anything.  What we will be using is the 0x02 command instead of 0x11 for on or 0x13 for OFF.  What I has able to find was the higher numbers after that worked. I’ll show you what

Ive got and show examples after.  In my case I couldnt send request using the regular PLC commands so I ended using the low level calls using the sendhex function, that article can be found here

More ways to speak to your Insteon Devices

For the examples my PLC is # “0D 51 32” and my Thermostat is “01 02 03“.

0x6b – Bit 2 – Get Thermostat Mode (Returned is 00=off,01=Heat,02=Cool,03=Auto,04=Fan)

 
	'Send

	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 02"	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

	'You should get the reponse on the Last Bit of your reponse.  For example
	04 01 02 03 0D 51 32 26 6B 02

	So in this case 0x02 Means the device is on COOL.

0x6b – Bit 3 – Get Temperature (Returned is the temperature, you convert to decimal and divide by two)

	'Send
	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 03")
	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command
	'You should get the reponse on the Last Bit of your reponse.  For example
	04 01 02 03 0D 51 32 26 6B 9A 
	So in this case 0x9A Converted to decimal is 154 divide
        that by two and you get 77 degrees!!

0x6b - Bit 4 - Set to Heat
'Send

Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 04")

Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

0x6b - Bit 5 - Set to Cool
'Send

Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 05")

Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command
0x6b – Bit 6 – Set to Auto (To switch automatically from Cool to Heat depending on your settings)

	'Send
	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 06")
	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

0x6b – Bit 7 – Fan on

	'Send
	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 07")
	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

0x6b – Bit 8 – Fan off

	'Send
	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 08")
	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

0x6b – Bit 9 – All Off

	'Send
	Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6B 09")
	Sm.SendPLCHex("02 46 01 42 10 9F") ' Execute my command

Setting the Cool / Heat Thermostat Temperature

Here insteon of 0x6B we will be using the 0x6C for Cool and 0x6D for HEAT.  So lets say you’ve set your device to Cool and want to lower it to 75 Degrees.  Just like when we read the temperature, when we set it we need to multiply the requested value * 2 and convert it to HEX.  In the sample below the variable Set_Temp holds what we want it to.  The next statement converts it to HEX and *2 and presto!

'This is the temperature we want to set Cool to!
Set_Temp="75"
Dim Temp As String = Hex(Set_Temp * 2)
Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6C " + Temp)
Sm.SendPLCHex("02 46 01 42 10 9F")

'This is the temperature we want to set heat to!
Set_Temp="70"
Dim Temp As String = Hex(Set_Temp * 2)
Sm.SendPLCHex("02 40 01 A1 00 09 FD 9B 0D 51 32 01 02 03 05 6D " + Temp)
Sm.SendPLCHex("02 46 01 42 10 9F")

Hope this works for you and its working great for me.  Each hour I poll the temperature and as part of that routine I poll my thermostat to keey the information up to date. I’ll post more as I find out!

Part 2.

As requested, here are some live examples,  this is of course using the SDM library in VB 2005, the same works for VB6.
Since my blog is really about my home project, a VERY GOOD site,  which is the one I used to start which has lots of specs and examples in VB6 about these commands. Its called Efundies.com, I wouldn’t like to re-invent the wheel.

My examples are using the SDM.SendinsteonRaw command, I find them faster since you don’t wait for a return.  For our examples we can use the source as “00 00 00” or the actually # on the PLC and the
rate is the actual intensity of the command. you can also use the sm.SendINSTEON(Device ID,command 1, command 2,hops) but it will wait for a reply.  I like to catch the response on the way back. And example using that command would be
sm.SetOnLevelText(“07.B1.12”, “100%”) – And here you DO have to use the dots. 🙂  A list of most of the commands that can be used when the SDM is properly load are here

We’ll use as examples for our program that the device we want to control is

In our program previously defined,
You can download the SDM device manager here.  Also some information regarding the PLC can be found here (This is the one I have) – worth every $

Option Explicit on
Friend WithEvents Sm As SDM3Server.SDM3

 Public Sub MainMenu_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
 Sm = New SDM3Server.SDM3  - Create a instance of the SDM using (SM)

 Dim Mac as string = "11 22 BB"
 Dim Rate as integer = 255

Mac = “11 22 BB”
Rate = Intensity of the device (Since we are using raw commands this runs from 0,256 and needs to be converted to HEX”
The last #3, which is the Hops= I keep as 3 (Always works for me.)

Notes: All values are in HEX, also you need to put spaces in your device address, in my case I pull them off a SQL Database but they come in as “11 22 33” if you put (.) dots or any other characters the command wont work.

Turn onSm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 11 ” + Hex(Rate), 3) – Turn on device to the desired rate to 255 is the same as Sm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 11 FF“), 3) – Turn on 100%
This will turn on the device at the predefined RAMP rate so if you have setup a slow ramp rate this is the one to use.  For example ICON Dimmers have no ramp rate (options) so this will turn on at .1 seconds

Turn on fastSm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 12 ” + Hex(Rate), 3) – Turn on device to the desired rate to 255 is the same as Sm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 11 FF“), 3) – Turn on 100%
This will turn on the device at fast redgardless of the  predefined RAMP rate.

Turn offSm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 13 00″, 3)
This will turn off the device at the predefined RAMP rate so if you have setup a slow ramp rate this is the one to use.

Turn off fastSm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 14 ” + Hex(Rate), 3) – Turn on device to the desired rate to 255 is the same as Sm.SendINSTEONRaw(“00 00 00 ” + Mac + ” 05 11 FF“), 3) – Turn on 100%
This will turn on the device at fast redgardless of the  predefined RAMP rate. For example ICON Dimmers have no ramp rate (options) so this will turn off at .1 seconds

Brighten up one step sm.SendINSTEONRaw(“00 00 00 “+Mac+” 05 15 00″, 3)
Each device has 32 levels of so this will just bump down or up one.  Good for dimming without knowing the previous value.  You can dim to 0.

Dim down one step sm.SendINSTEONRaw(“00 00 00 “+Mac+” 05 16 00″, 3)
Each device has 32 levels of so this will just bump down or up one.  Good for dimming without knowing the previous value.  You can dim to 0.

Get status of device – sm.SendINSTEONRaw(“00 00 00 11 22 BB 05 19 00″, 3)
Using Alternet command sm.GetOnLevelText “11.22.BB”

Sending a Inteson group message; Groups allow you to send messages to a set of devices (1,2,10,100,200 with one command) Only bad things is you dont get a reply from the devices
I have found I had to run this twice sometimes but (We’ll get to groups later) .

Turn off group #20 (Remember HEX!) – sm.SendINSTEONRaw(“00 00 00 00 00 20 CF 13 00″, 3) ‘ SEND broadcast group 20 OFF!

Turn on group #20 – sm.SendINSTEONRaw(“00 00 00 00 00 20 CF 11 FF”, 3) ‘ SEND broadcast group 20 ON

The PLC also send X10 commands, for this I use theSendX10 command, this command WILL pause and wait for a response. For example

Sm.SendX10(“D02,DON”) ‘ TURN ON Device D02
Sm.SendX10(“D02,DOFF”) ‘ TURN ON Device D02