How to deal with X10 data


Recommended Posts

I'm not completely sure that DF Channels is going to be your best bet, at least not initially. First try and get stuff into variables and use sequences. Then you can work on channels.

As for getting the data, the transmit is easy, just use:

device.mydevice.write("$>2800008C#")

Presumably you would generate that string dynamically based on the actual id.

Reading is not much harder. Fortunately it appears they use the # as an end of line delimiter, so you can get a line just by doing:

private datain = device.mydevice.readuntil(35)

where 35 is the ascii code for #

Once you get the line, you can use the parse() function to split it out. It appears each parameter is separated by a space:

datain = parse(datain, -1, " ")

This will make datain be an array of strings. If there is no data, then numrows(datain) will be 1, so that's an easy check. Otherwise, you can parse through each response with a simple loop:

for (private i = 1, i < numrows(datain), i++)
   // do something with datain[i]
endfor

When I say do something, I mean use the various string functions of DAQFactory to parse a particular item.

As an example, if you received this line:

$<2800! C05C05 CONCON9B#

once you did the parse():

datain[0] would = "$<2800!"

datain[1] would = "C05C05"

datain[2] would = "CONCON9B"

The # would actually not be in the string read (datain before the parse) since it was the end of line delimiter.

Link to comment
Share on other sites

Thanks

Good advice on the channels, get data into variables first.

You pointed me in the right direction and with enough info to be dangerous. Don't blame me if your lights turn off and on. :lol:

if (SysTime() < 16h) // if its not 4pm yet

WaitUntil(16h) // wait until 4pm

else

WaitUntil(16h+86400) // otherwise, wait until 4pm tomorrow

endif

while (1)

do something...

WaitUntil(16h + 86400) // wait until 4pm tomorrow

endwhile

This code snip from the manual to do something everyday at 4pm, for 4:15pm you would use:

if (SysTime() < 16h15m

rje

Link to comment
Share on other sites

Yes, but personally, I use something more like this:

private nexttime = 16h15m
if (nexttime &lt; systime())
   nexttime += 86400
endif
while (1)
   waituntil(nexttime)
   // do something
   nexttime += 86400
endwhile

And in actual fact, I would do this:

private nexttime = 16h15m
if (nexttime &lt; systime())
   nexttime += 86400
endif

while (1)
   if (systime() &gt; nexttime) 
	  // do something
	  nexttime += 86400  
   endif
   delay(1)
endwhile

Its actually not quite as efficient this second way since the script loops every second, but it gives you more flexibility and allows you to do other stuff in the same loop while waiting. A personal preference really.

Link to comment
Share on other sites

I don't think I'm following the while (1), could you explain how it works?

while (1)
   waituntil(nexttime)
   // do something
   nexttime += 86400
endwhile

Thanks

rje

Link to comment
Share on other sites

In DAQFactory, like many other programming languages, non-zero values are consider "true" and 0 is considered "false". 1 is typically used for "true", so while(1) means loop forever, since 1 is always true. The script thus loops forever, doing something at 4:15 every day.

Link to comment
Share on other sites

  • 2 weeks later...

Ok, I understand what while (1) means.

private nexttime = 16h15m
if (nexttime &lt; systime())
   nexttime += 86400
endif

while (1)
   if (systime() &gt; nexttime) 
	  // do something
	  nexttime += 86400  
   endif
   delay(1)
endwhile

For this code, after the endwhile would it return to the while (1) or would it return to the if?

This code works fine for a single 'do something' at a certain time but how to deal with 20 individual 'do somethings' all at various times. This is where I'm locking up.

Thanks

rje

Link to comment
Share on other sites

It would return to the while(1).

20 different do somethings? Just create 20 different sequences. That is the easy solution, although not very elegant. There are more elegant solutions, but creating 20 sequences isn't that bad and is easier to understand if you are just starting out.

Link to comment
Share on other sites

  • 1 month later...

OK, I have most things working except one and my forehead is bruised and bloodied from banging it off the brick wall. ;)

The X10 unit I poll can store multiple codes it receives, so when polled I can get this:

Tx: $>2800008C#

Rx: $<2800! C04C04 COFFCOFF C04C04 CONCON C04C04 COFFCOFF C04C04 CONCON7B#

Parsing it out is not a problem but dealing with the last parsed data is. The last parsed "packet" always has the checksum value and the delimiter #. In the above example how would I drop the '7B#' off the last parsed data? Remember the parsed data can vary in length.

I could post my code attempts but none have worked.

Any X10 transmission from within my home, the last parsed 'packet' should always be xONxON7B# or xOFFxOFF7B#. With x being A - Z and the checksum 7B will also vary depending on the whole packet.

Thanks

Link to comment
Share on other sites

I'm on the right track but here's where I'm going wrong.

Data_In = Device.TI103.ReadUntil(35)

// What DataIn contains - $<2800! C04C04 COFFCOFF C04C04 CONCON C04C04 COFFCOFF C04C04 CONCON7B#

Data = Parse(DataIn, -1, " ")

//This should give me Data[0], Data[1]......Data[8] right?

private i = NumRows(Data)

//This to get the last Data[?} number, right? So far all works but when I try to do anything on Data I get the Error saying a parameter is empty.

So close yet so far!

Link to comment
Share on other sites

  • 2 weeks later...

Ok, #63, this is what I have working, may not be pretty but it is functional.

// test to check incoming X10

global C06 = 0														   //set to zero as per private variables

private string Data_In
private string Data

private C06x = 0														//set variables to zero, will be done in a first run sequence later
private C06ON = 0
private C06OFF = 0


while (1)

   Device.TI103.Purge()
   Device.TI103.Write ("$&gt;2800008C#")								   //request data command
   Data_In = Device.TI103.ReadUntil(35)

   Data = parse(Data_In, -1, " ")

   private Packet = (NumRows(Data))

   if (Packet &gt;&gt; 1)													 // parsed data has to be longer than 1 if any data on power line has been received

		 private Length = NumRows(Data)								 // get total length of data received

		 private i = Length - 1										 // subtract 1 because of 0 indexing

		 Data[i] = Left(Data[i], GetLength(Data[i]) - 3)				// strip off check sum and delimiter on last parsed data

			for (private p = 1, p &lt; numrows(Data), p++)

			   switch												   //compare to see what we got

				  case (Data[p] == "C06C06")
				  C06x = 2

				  case (Data[p] == "CONCON")
				  C06ON = 4

				  case (Data[p] == "COFFCOFF")
				  C06OFF = 6

			   endcase

			endfor

		 Packet = 0													 //clear packet count for next read

   endif

   if ((C06x + C06ON + C06OFF) == 6)									//C06C06 CONCON is received
	  C06 = 1														   //set master global variable
	  C06x = 0
	  C06ON = 0
	  private string C06_1 = FormatDateTime("C06 ON: %c", SysTime())	//need to log this to a file, further work needed
	  ? C06_1														   //out to command window
   endif

   if ((C06x + C06ON + C06OFF) == 8)									//C06C06 COFFCOFF is received
	  C06 = 0														   //set master global variable
	  C06x = 0
	  C06OFF = 0
	  private string C06_0 = FormatDateTime("C06 OFF: %c", SysTime())
	  ? C06_0														   //out to command window
   endif

Delay(2)

endwhile

This is tested with only 1 X10 code on the powerline, C06 ON & C06 OFF but in real life I will have to check for about 30 X10 codes.

Question is, before I enter code for a few days is the case/switch the right thing to be using?

Thanks

rje

Link to comment
Share on other sites

Switch case should be used in place of if/elseif type of structure where only one of the items will ever be true (or at least only one will ever want to execute).

Also:

if (Packet >> 1)

is incorrect. >> means shift right, so this if will evaluate to true whenever packet > 1, which just happens to work out in your case, but its not really what you meant. You want just:

if (packet > 1)

Link to comment
Share on other sites

Not sure if I understand your answer.

I'll never know what I will receive but assuming I only receive this: C04C04 & COFFCOFF (afer parsing).

Now I must compare these 2 to a list to see if anything should be done.

From your answer I gather I should use mutiple if/elseif statements and not case/switch.

Roger on the (packet > 1).

Thanks

Link to comment
Share on other sites

No, switch/case replaces if/elseif. It executes the first case() that matches. So, lets say you had:

switch
   case (x &gt; 3)
	   do 1st thing
   case (x &gt; 1)
	   do 2nd thing
endcase

If x > 3, then only the 1st thing executes. The 2nd thing will only execute if x > 1 but <= 3. If you need it to do both if x > 3, then you need two separate ifs:

if (x &gt; 3)
   do 1st thing
endif
if (x &gt; 1)
   do 2nd thing
endif

See the difference?

The switch/case is actually the same as:

if (x &gt; 3)
   do 1st thing
else
   if (x &gt; 1)
	  do 2nd thing
   endif
endif

but as you can imagine, if you had more than a couple items, the if/else if structure would become hard to read with all the else, if, endifs and proper indentation. The switch/case is much clearer.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.