Re: CRC16 help
Posted: Thu Sep 27, 2012 6:31 am
by aquarat
Hey Jameson
I've finished installing one of your company's meters in one of our tenant's premises... I'll upload some photos at some point. Getting a cellphone signal was a mission, but it's all working now.
It's quite cool being able to see voltage differences between home and the first field meter (home is around 238 Volts, meter in the field is 221 V).
The layout of connectivity looks like this :
Code: Select all
Client premises
|------------------------------------------------------------------------------------------|
EKM OmniMeter ---(RS-485)---> iSerial ---(Ethernet)---> Mikrotik Router ---(VPN over 3G)---> Central VPN server ---(Ethernet)---> My meter reading system
I can currently access the freshly installed EKM meter from my current location, which is connected through another VPN over ADSL to my main VPN server... ahhh isn't the internet amazing ?
This is what the debugging output of my application looks like in the terminal (all this data also makes its way into the database, the db data is more complete than the terminal debugging output) :
Code: Select all
230 : Thu Sep 27 14:58:23 SAST 2012 : EKM CRC : 492e Device CRC : 2e57
231 : Thu Sep 27 14:58:23 SAST 2012 : Meter : 000000012727
232 : Thu Sep 27 14:58:23 SAST 2012 : Voltage 1 : 238.9
233 : Thu Sep 27 14:58:23 SAST 2012 : Voltage 2 : 0.0
234 : Thu Sep 27 14:58:23 SAST 2012 : Voltage 3 : 0.0
235 : Thu Sep 27 14:58:23 SAST 2012 : kWh Total : 296.0
236 : Thu Sep 27 14:58:23 SAST 2012 : kWh 1 : 155.2
237 : Thu Sep 27 14:58:23 SAST 2012 : kWh 2 : 140.8
238 : Thu Sep 27 14:58:23 SAST 2012 : kWh 3 : 0.0
239 : Thu Sep 27 14:58:23 SAST 2012 : Power 1 : 1266
240 : Thu Sep 27 14:58:23 SAST 2012 : Power 2 : 0
241 : Thu Sep 27 14:58:23 SAST 2012 : Power 3 : 0
242 : Thu Sep 27 14:58:23 SAST 2012 : Power Total : 1266
243 : Thu Sep 27 14:58:41 SAST 2012 : EKM CRC : 691b Device CRC : 1af
244 : Thu Sep 27 14:58:41 SAST 2012 : Meter : 000000012706
245 : Thu Sep 27 14:58:41 SAST 2012 : Voltage 1 : 226.2
246 : Thu Sep 27 14:58:41 SAST 2012 : Voltage 2 : 0.0
247 : Thu Sep 27 14:58:41 SAST 2012 : Voltage 3 : 0.0
248 : Thu Sep 27 14:58:41 SAST 2012 : kWh Total : 85.2
249 : Thu Sep 27 14:58:41 SAST 2012 : kWh 1 : 71.1
250 : Thu Sep 27 14:58:41 SAST 2012 : kWh 2 : 14.1
251 : Thu Sep 27 14:58:41 SAST 2012 : kWh 3 : 0.0
252 : Thu Sep 27 14:58:41 SAST 2012 : Power 1 : 3318
253 : Thu Sep 27 14:58:41 SAST 2012 : Power 2 : 0
254 : Thu Sep 27 14:58:41 SAST 2012 : Power 3 : 0
255 : Thu Sep 27 14:58:41 SAST 2012 : Power Total : 3318
This is running on a Pi but could easily run on any system, including x86 and Windows, without recompilation. There are still some minor issues in my application; I think I have the incorrect offset for the kwh2 data, as both of these meters are only connected to single phase. However the total kwh is my major point of interest and reliably matches what's displayed on the meter.
At the moment I'm using the InputStreamReader class in java, as opposed to the BufferedInputStreamReader... this might be causing the trouble with short responses, but certainly my application reliably reads more than 1 sample per minute, which is well in excess of my requirements (I just need to know how much power is being used on a monthly basis... but I love seeing all the other data and having more samples for better resolution... it's just cool).
Thanks for making such easy to use documentation available on your company's meter protocols, it's really been of great help
.
Have you only read your meters through iSerials or have you also tried reading them through UART or USB? We would be happy to send you a USB converter to get you going if you need one.
I've only read data off the meters so far using the iSerials. I've experimented a great deal with RS232 and TTL UART comms before and so far I've had bad luck with USB-RS232 adapters... they seem to die after a random number of hours in Linux. Maybe the problem's been solved? The Raspberry Pi has a TTL UART that forms part of it's GPIO header, I regularly use this through a level shifter to talk to RS232 devices (APRS modem, Oregon Scientific weather station, etc.)... a similar solution may be possible for RS-485... but it doesn't really make sense for my scenario; I want my logging system to be separate from the meters for security purposes. If I were to log the data using Raspberry Pis at the site of the meter I'd still have to deal with getting that data to a central location, where I have control of it. That said, getting my programme to read data from the meters directly using a USB to RS-485 adapter would probably be extremely easy. I know from past experiences that the libraries used to read data from UARTs behave almost identically when compared with TCP sockets (from my code's perspective). I could just look for "/dev" or "COM" in the "meter0address" argument in my configuration file and then if I find one of those tokens assume that the meter is directly attached.
I must say, though, that I do like the iSerials... they're small and they're encased in metal, they look perfectly at home in a DB box.
Now that this is working I've asked our electrical contractors to install additional boxes for metering, which will hopefully be ready by next week.
Photos :
The photos are being hosted on my ADSL line... on a Raspberry Pi haha (I have many of them
).
In the image of the box without it's main cover you can see :
1) A Mikrotik router on the lower left with a USB 3G dongle attached and attached to that an antenna extender.
2) The iSerial is obscured by the box, but it sits just underneath the plus point.
3) Obviously the EKM Omnimeter is present in the top right and you can just barely make out it's CT in the top of the box on the left.
4) Another power meter is present... but it's quite dumb and was installed as the result of a misunderstanding.
Above : A little less related; a Pi with a TTL->RS232 level shifter attached and that in turn attached to a USB-RS232 converter.
Re: CRC16 help
Posted: Tue Mar 10, 2015 1:00 pm
by cliff@hawkrdg.org
OK, so after a bit of head-banging, here is the javascript code to use this in a webapp. You can submit hex strings as str = String.fromCharCode(0x52, 0x31, 0x02, 0x30, 0x30, 0x31, 0x31, 0x03); - ReadLastKwh. I built a simple library of the calls I needed. This all works fine inside of a web app served off of a node.js server using angular.js and couchdb for data binding and storage.
//-- BY ALL THE GODS, FIX THIS FORMATTING SO IT LOOKS LIKE REAL JAVASCRIPT --
var crcHexString = "";
ekmCrcLut = [
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
];
convertStringToUint8Array = function( str ) {
var a8 = new Uint8Array( str.length ), data;
data = str.split("");
data.forEach( function(ch,cnt) {
a8[cnt] = ch.charCodeAt(0);
} );
return a8;
}
ekmCheckCrc = function( str ) {
var crc = 0xffff, data = main.convertStringToUint8Array( str );
console.log( 'calc crc16 for ' + data );
for (var i = 0; i < data.length; i++ ) {
crc = (crc >> 8) ^ main.ekmCrcLut[(crc ^ data) & 0xff];
}
crc = (crc << 8) | (crc >> 8); // reverse the bytes
crc &= 0x7f7f; // rip each byte to 7-bits
crcHexString.txtCRC16 = crc.toString(16); // text for page display
return crc
}
//-- BY ALL THE GODS, FIX THIS FORMATTING SO IT LOOKS LIKE REAL JAVASCRIPT --