My water meter (with a Neptune T-10 encoder) is connected to an external RF transmitter (a Neptune R900) to allow drive-by meter readings. Great! I’d like that data for my home monitoring system. (The bottom line is .)
There’s a cool 900 MHz utility meter monitor tool mentioned in . Unfortunately, while it can receive the transmissions from an R900, it can’t decode the data (yet). I sent a note to Greg at and asked if I could help with development of the R900 code, but what’s left would involve crypto stuff I know nothing about. Nice try. I guess I’ll have to try to eavesdrop on the data going from the meter to the transmitter.
The 3-wire connection between the two seems to consist of common, data (from meter to transmitter), and clock/power (from transmitter to meter). The transmitter apparently polls the meter periodically by sending a string of clock pulses to it. The meter responds by putting (usage) data on the data line, clearly clocked out by the clock pulses from the transmitter. I can see both the clocks and the data; now I just need to decode the data so my home monitoring system can use it.
Update 9/4/12: After staring at it for a long time I noticed a pattern: There’s always a 1/2 clock cycle lo “blip” on the low half of every 16th clock cycle, always followed by a high blip of either 1/2 or 3 1/2 clock cycles. And those are the ONLY instances of 1/2 cycle nonsense. Otherwise all data line transitions are reassuringly on hi->lo clock edges. Those statements apply to both sections of the communication capture: The first ~500 clock cycles of 50% duty cycle and 0.3ms width, and the last ~250 clock cycles of 33% duty cycle and 0.42ms width. (What’s that about??)
So the half-cycle stuff is clearly some kind of frame delimiter. But with 15 clock cycles of usable data time per frame, the bit encoding is still unclear. More head scratching ahead.
To avoid conflicts with my someday higher frequency polls and the polls from the R900, I needed to know how often the R900 actually polls. I set up an Arduino to look for lo-hi transitions on the clock line and timestamp them. (It sleeps 1000 ms after it logs a transition to ignore the ~0.25 seconds of actual data.) The R900 is quite uniform in polling about every 3030 seconds.
Even more interesting is that the polls are sometimes repeated after a second or few, up to 6 times in the day or two I’ve been logging. Most polls are not repeated. A first guess is that a repeat poll is sent when some kind of checksum fails.
Update 9/6/12: It occurred to me that my simple assumption that the reader provides a series of clock pulses and the encoder drove the data line might not be completely right. (Especially in light of the change in clock duty cycle after the first 500 or so clock pulses.) To see who was really driving the bus (?), I thought I’d isolate the two sides with Schottky diodes oriented so the R900 power/clock could get thru and the data line high states from the encoder could get thru. (Two diodes pointing in opposite directions.) I’ll spend 2 more channels of the USBee SX and monitor on both sides of both diodes. I’m hoping the logic thresholds will let me see if there is any difference on the two sides of the diodes, indicating a more interesting story than I originally assumed.
The only Schottkys I had were SMT, so I sliced two insulating slots in a bit of scrap copper clad, soldered the diodes on, and set it up so it would be easy to insert inline in the black (clock/power) and red (data) lines. (Green is common and will remain connected.)
I didn’t want to interrupt an R900 poll (though I don’t think that would cause any real trouble), so I needed to know when to expect the next poll. My Arduino sketch logging time between polls was still running, but it didn’t tell me how long ’til the next poll. I added a Serial.available() check so any keypress will print time since last event (and, assuming 3030 secs between, estimated time ’til next). Now I know how much time I have to remove my spring contacts, rewire the cable to the R900, reposition my spring contacts, and set up the USBee SX.
Grumpf. The PC software had somehow lost contact with the USBee module and wouldn’t run and capture. I had to shut it down, unplug module, replug module, restart software, and set up for the triggered capture again. In doing that, I missed the poll event. Grumpf.
And then several more misses. Can’t find the USBee help files – bad link on their web site!
OK – got a capture. (USBee setup: set CLK input so you can change Capture on TRIG to hi; set CLK back to output; set 1st 2 cols on clock sig to lo, hi; click Acquire.) Clock is identical on both sides of the diode. Good – no funny business from the encoder (like providing the clock!). So I have to believe if I injected a clock pulse stream, I’d elicit data. But the data line is not identical. Data is clearly driven on the encoder side. Unfortunately the signal on the R900 side goes high and stays high. Very high input impedance? Anyway, I don’t think the R900 gets the data. Its clock stream extends way longer than normal. Jumpered around the data line diode. New capture much better, but not quite like first one. That capture is water4.ulb.
The Arduino monitoring polls also saw re-polls until I jumpered the data line diode, then R900 got data first poll. The bad news is that now I still can’t tell if the R900 ever writes on the data line.
Update 9/9/12: OK – I think I’ve won. The apparent re-polls from the R900 when the (weak-drive) data line was connected directly to an Arduino input caused me to add a simple buffer to reduce the loading on the encoder’s data line. That seemed to help. After I fixed dumb bugs in my code, the Arduino started getting data. Then I replaced the function that waited for a clock edge with code that toggled a bit so the Arduino provided the clocks. Once I could generate my own clocks, I made a lot faster progress than back when I had to wait 50 minutes for the R900’s next poll!
The (brown) clock is regular, with a period of ~300 μsec. The basic bit time is from clock falling edge to the next falling edge. Five bits of data (red line) are shown – pretty obvious.
There’s a frame delimiter (Frm) consisting of a half-cycle of low (starting on clock falling edge) followed by a half cycle of high (starting on clock rising edge). This frame mark (from the register encoder) occurs regularly every 16th full clock pulse. That gives us 15 bits of data per frame. When data bits are being clocked out, a data line transition is never allowed on a rising edge, making the frame mark completely unique.
Looking at the “sync” frame, here’s how the data is decoded. After the frame mark, we take blocks of 4 bit times and express them in binary. With LSB first, the bits in each nibble are reversed, and all the nibbles are reversed. There are only 15 data bits, so the most significant bit (X) is missing; we assume it’s a zero.
Very interestingly, the only nibble values that I’ve ever seen are 4 and 7. Now, for reasons I don’t understand, we assign a nibble value of 4 to be logical “1” and nibble value of 7 to be logical “0”. The sync frame above then has the logical value 1110 – or 0xE.
One shred of hope was in the two phases of the R900’s poll, with different duty cycles. Might that second, 33% duty cycle poll elicit data from those lower two wheels and maybe even the big red hand? I found an early R900-clocked capture and manually decoded the data. Nope. Same patterns and same data as the 50% duty cycle poll. Bummer.
A few more observations about the whole data sequence. Starting from the clock line going from 0V to 5V (rising edge), we have the second half of a frame marker, followed by 6 frames of the 0xE sync pattern. Then we have 4 frames containing the (most significant) meter usage wheel data, 5 more frames of 0xE, then one frame of 0xF. Then the whole pattern repeats. The R900 poll sequence provided 300 μsec 50% duty cycle clocks for: 6 0xE, 4 data, 5 0xE, 1 0xF, 6 0xE, 4 data, 5 0xE; then 424 μsec 33% duty cycle (1 lo, 2 hi) clocks for 1 0xF, 6 0xE, 4 data, 5 0xE.
I tried 100 frames’ worth of clocks and the pattern of 6 sync, 4 data, 5 sync, 1 0xF just repeated and repeated. And no checksums – My earlier guess about a checksum fail was wrong. I guess the data integrity check is just to watch the data for more than one cycle and make sure it’s the same.
Final Arduino code to generate clocks and read data is .