Time sync to a Modbus device
-
I have a set of Modbus devices that I would like to send time syncs to. They accept the sync as a single type 16 Modbus message to a set of 7 registers. Can I use a Meta, Scripting or Virtual data source triggered every hour to do this? I have looked at the examples and there does not seem to be one that covers sending data to multiple registers in one stream. Any advice would be helpful here!
-
Hi malcolmbco,
I think this should be possible. You will want to create a "Fixed length string" type Modbus point with the offset that begins this register set, then use a scripting data source to format the time into the bytes of the string, like,
function getTimeString() { var base = new Date().getTime().toString(16); while(base.length < 28) //four hex characters per register base = "0" + base; var result = ""; for(var k = 0; k < 14; k+=1) { //two chars per byte, two bytes per register result += String.fromCharCode("0x" + base.substr(k, 2)); } return result; } print(getTimeString());
-
Philip,
Thanks for the response.
The registers are mapped as year, month, day of month, day of week, hours, minutes, seconds with the binary value in the lsb of each register. I made the data type a fixed length string so I could use String.fromCharCode to set them by position.
I assigned a MetaDataSource with the cron set to once an hour to trigger the script. The script is as follows (the data point for the time is p18). I tested this on a windows platform and noticed that the cron setup does not seem to affect the execution, the script was being executed continuously until I made it only do the set on the hour turn over using an if statement. Is there an issue with cron on this platform?
// set time in room controller var currentTime = new Date(); var year = currentTime.getFullYear(); var month = currentTime.getMonth() + 1; var dayOfMonth = currentTime.getDate(); var dayOfWeek = currentTime.getDay(); var hours = currentTime.getHours(); var minutes = currentTime.getMinutes(); var seconds = currentTime.getSeconds(); if ((seconds === 0) && (minutes === 0)) { var res = String.fromCharCode(0,year-2000,0,month,0,dayOfMonth,0,dayOfWeek,0,hours,0,minutes,0,seconds); p18.set(res); }
Thanks again!
Malcolm
-
Nice! One has to wonder a little why they need year, month, day of month and then also day of week... But it makes more sense than a 8byte long timestamp being put into 28 bytes!
My guess is that you've set p18 to update the context, and that's why you were seeing that. In the context table above the Meta point's script body, make certain all rows are unchecked to update the context if you wish it to execute on cron only. There are not known issues with the cron specific to windows. The only issue I'm aware of with the cron is it errors if you specify a year in the past (technically Mango cron patterns don't support year, but it does work most of the time).
-
It looks like I steered you wrong a little bit, as you alerted me over the phone. You were correct that the ASCII character encoding set up wasn't supported arbitrary bit patterns (anything over 127 was getting the wrong byte sent). So, what you can do is modify the alphanumeric modbus point to have a different character encoding. I used UTF16 and then changed my String.fromCharCode() to process two bytes at time, which worked to send out 0xFFFF to the target device.
-
You were correct, update context was set. I cleared it and the cron interval now works fine. I did change the data type to UTF16 and can read the rtc data back just fine. However, writing still seems to have an issue. The first word sent is always 0xFEFF and the rest of the data sent is truncated by one word. I checked this by sniffing the data stream on the modbus. Any ideas?
Malcolm -
Try out UTF-16BE or UTF-16LE which will eliminate the byte-order marking, 0xFEFF
-
Yes, UTF-16BE worked great. I have time updates going to two different devices every hour.
Thanks!
Malcolm -
Certainly! Glad to hear you got it working!