merbanan / rtl_433

Program to decode radio transmissions from devices on the ISM bands (and other frequencies)
GNU General Public License v2.0
6.04k stars 1.31k forks source link

Decoding Flowis water meter #2317

Closed vierundvierzig closed 1 year ago

vierundvierzig commented 1 year ago

Originally topic was started on wmbusmeters project.

Now I am in place that it should be decode from the beginning using rtl_433. I can grab some sample files from today: sample_files.zip

I tried to analyze them but it says nothing to me...

Any help will be greatly appreciated!

zuckschwerdt commented 1 year ago

It's 100 kbps FSK, so could be M-Bus Mode C / T (or just similar). This gets the data: rtl_433 -R 0 -X 'n=name,m=FSK_PCM,s=10,l=10,r=500'

g010_868M_1000k.cu8: {233}8008aa22d391d3911201f60f000f81c3f0607cef000000470000e77ff78
g011_868M_1000k.cu8: {162}c000555561c8e9c88981df27a8870000000000000 {18}fcb20
g012_868M_1000k.cu8: {234}800002aad391d3911201be4f410e81da74607cff000000450000e71f8dc
g013_868M_1000k.cu8: {161}8000828bc381c3911303be0f010e0000000000000 {17}fcb20
g014_868M_1000k.cu8: {233}802aaaaad381f3811201f64f410f81f074607cff000000450000a7977d8
g015_868M_1000k.cu8: {161}80003aa8c391d3911303f60f510e0000000000000
merbanan commented 1 year ago

The signals look ok but you need the proper demod and longer reset value, so rtl_433 -f 868M -s 1000k -X 'n=name,m=FSK_PCM,s=10,l=10,r=5000'

 g010_868M_1000k.cu8: {229}aaaaaaa d391 d391 [1201] b64f 510e [81c374605cef000000450000a5 [5ff7]
 g012_868M_1000k.cu8: {228}aaaaaaa d391 d391 [1201] b64f 510e [81da74605cef000000450000a5 [1b8d]
 g014_868M_1000k.cu8: {228}aaaaaaa d391 d391 [1201] b64f 510e [81f074605cef000000450000a5 [977d]
 g011_868M_1000k.cu8: {236}aaaaaaa d391 d391 [1302] b64f 510e 0000000000000000000000000000 [fcb2]
 g013_868M_1000k.cu8: {235}aaaaaaa d391 d391 [1302] b64f 510e 0000000000000000000000000001 [f964]
 g015_868M_1000k.cu8: {237}aaaaaaa d391 d391 [1302] b64f 510e 0000000000000000000000000000 [fcb2]

So the signal consist of a preamble and then some header. From the signals we here see 2 different packets 201 and 302. Then some more data and then some payload depending on the packet and then at the end there are 4 values that might be a CRC.

merbanan commented 1 year ago

Now we need a large set of received messages (1000 would be nice to start with). Then we need to try to match it with possible data, serial number and the meter value. We need to figure out the shift also. aad391 has a 25% chance of being correct.

If the collection part is boring then build a webcam rig that grabs a photo whenever there is a new transmission.

merbanan commented 1 year ago

And for the record the long sequence of zeroes in one type of message de-syncs the bitstream. So this is not wmbus this is some proprietary scheme. The existence of desyncs indicates that it is not that well designed and most likely only one user of the protocol.

Anyway we should be able to fix the bit stream if we detect a long period of zeroes. It looks like the message after the preamble is 200 bits long.

zuckschwerdt commented 1 year ago

The d391 d391 is a known sync word (rojaflex.c, marlec_solar.c, archos_tbh.c, maverick_xr30.c). 16-bit chunking from there on looks promising, though the first three are a byte shorter. The g013 is broken, all other check out with CRC-16 poly 0x8005 init 0xffff. (I edited your code grouping)

merbanan commented 1 year ago

./reveng -s -w 16 d391d3911201b64f510e81c374605cef000000450000a55ff7 d391d3911201b64f510e81da74605cef000000450000a51b8d d391d3911201b64f510e81f074605cef000000450000a5977d width=16 poly=0x8005 init=0x1818 refin=false refout=false xorout=0x0000 check=0xabbd residue=0x0000 name=(none)

merbanan commented 1 year ago

So poly poly=0x8005 looks good. And we can then fix the bit stream if it gets desynced.

zuckschwerdt commented 1 year ago

Start after the sync for a nice init of 0xffff :)

merbanan commented 1 year ago

Yeah, init and check looked off.

zuckschwerdt commented 1 year ago

g013 with one 0-bit inserted is 1302b64f510e000000000000000000000000000fcb2 and checks out ;)

merbanan commented 1 year ago

g013 with one 0-bit inserted is 1302b64f510e000000000000000000000000000fcb2 and checks out ;)

Desync but you now proved it can be handled.

merbanan commented 1 year ago

So @vierundvierzig, we now have a quite good understanding of the structure of the messages. You now need to vary one parameter and observe the change in message. From the picture we see 2 meters, that should help out to identify the meter id.

vierundvierzig commented 1 year ago

Wow, I am impressed of you guys :) I will do my best, but meters send signals when I am at work... As soon as I figure something out I let you know.

PS. They also send some additional information like:

EDIT: so for now we need just 1-2 change in readings? Or 1000? ;)

zuckschwerdt commented 1 year ago

The first byte (after the sync) is the length, so 12 (18) and 13 (19). This is very similar to Marlec Solar iBoost+ and Archos-TBH (but different bitrate), likely because it's based on a TI CC1100 I'd guess.

We can implement a decoder, but you will need to watch the payload (type 1 and type 2 above) and make deductions. If the fields after the type code are addresses/IDs, the this is the info you are looking for: 81f074605cef000000450000a5 -- the consumption value is that.

vierundvierzig commented 1 year ago

I took one meter (id: 240234918) to work but I can see on waterfall very strong, stable signal on 868.01MHz... Anyway, I changed the readings on it to 00000.251 and recorded some sample: sample_2402349718_00000251.zip I hope it will be ok. If yes, I can do some more readings.

zuckschwerdt commented 1 year ago

Yes, the codes are good:

aaaaaaa d391 d391 1201 a6b1 510e 81f996625cf1000000110000a5 7168
aaaaaaa d391 d391 1302 a6b1 510e 1c00000000000000000000000201 5ff4
aaaaaaa d391 d391 1201 a6b1 510e 811e97625cf1000000110000a5 0a87
aaaaaaa d391 d391 1302 a6b1 510e 1c00000000000000000000000201 5ff4
aaaaaaa d391 d391 1201 a6b1 510e 814497625cf1000000110000a5 1191
aaaaaaa d391 d391 1302 a6b1 510e 1c00000000000000000000000201 5ff9

Now we need a series of samples or codes with sample changes (counting up). Use e.g. rtl_433 -f 868M -s 1000k -X 'n=name,m=FSK_PCM,s=10,l=10,r=5000' to get codes and paste a list like:

{229}555555569c8e9c88900d358a88740fccb312e7880000008800052b8b40 [00000.251]
vierundvierzig commented 1 year ago
{230}555555569c8e9c88900d358a88740f373312e7a00000008800052a40d4 [00000.254]
{237}555555569c8e9c889815358a8870f80000000000000000000000080567f8 [00000.254]
{229}555555569c8e9c88900d358a887408273b12e7a00000008800052f93b0 [00000.254]
{237}555555569c8e9c889815358a8870f80000000000000000000000100acff8 [00000.254]
{230}555555569c8e9c88900d358a887408f73b12e7a00000008800052bb470 [00000.254]

{230}555555569c8e9c88900d358a88740d6f3b12e7c80000008800052e8f4c  [00000.259]
{236}555555569c8e9c889815358a887120000000000000000000000010017c7 [00000.259]
{230}555555569c8e9c88900d358a88740e5f3b12e7c80000008800052e07c0 [00000.259]
{236}555555569c8e9c889815358a887120000000000000000000000010017c7 [00000.259]
{230}555555569c8e9c88900d358a88740f2f3b12e7c80000008800052e6fa8 [00000.259]
{236}555555569c8e9c889815358a887120000000000000000000000010017c7 [00000.259]

{230}555555569c8e9c88900d358a887409cf4312e7f80000008800052e47c0 [00000.265]
{238}555555569c8e9c889815358a88715000000000000000000000000804ce54 [00000.265]
{229}555555569c8e9c88900d358a88740abf4312e7f80000008800052ad0b0 [00000.265]
{236}555555569c8e9c889815358a887150000000000000000000000010099ca [00000.265]
{230}555555569c8e9c88900d358a88740b8f4312e7f80000008800052ea724 [00000.265]
{237}555555569c8e9c889815358a887150000000000000000000000010099ca8 [00000.265]

{229}555555569c8e9c88900d358a8874081f4b12e0400800008800052d2d98 [00000.274]
{236}555555569c8e9c889815358a887198000000000000000000000010000d0 [00000.274]
{229}555555569c8e9c88900d358a887408ef4b12e0400800008800052d05b0 [00000.274]
{236}555555569c8e9c889815358a887198000000000000000000000010000d0 [00000.274]
{230}555555569c8e9c88900d358a887409bf4b12e040080000880005296230 [00000.274]
{237}555555569c8e9c889815358a887198000000000000000000000010000d08 [00000.274]

{229}555555569c8e9c88900d358a88740d875312e0700800008800052c6970 [00000.280]
{236}555555569c8e9c889815358a8871c800000000000000000000001000ada [00000.280]
{229}555555569c8e9c88900d358a88740eb75312e0700800008800052ce1f8 [00000.280]
{239}555555569c8e9c889815358a8871c80000000000000000000000080056d2 [00000.280]
{231}555555569c8e9c88900d358a88740fbf5312e0700800008800052a9d92 [00000.280]
{237}555555569c8e9c889815358a8871c800000000000000000000001000ada0 [00000.280]
zuckschwerdt commented 1 year ago

Very good. Drop in a BitBench like this (sorted by msg type here) and we do see some counters!

merbanan commented 1 year ago
{230}555555569c8e9c88900d358a88740[d]6f3b12e7c80000008800052e8f4c  [00000.259]
{230}555555569c8e9c88900d358a88740[e]5f3b12e7c80000008800052e07c0 [00000.259]
{230}555555569c8e9c88900d358a88740[f]2f3b12e7c80000008800052e6fa8 [00000.259]

{230}555555569c8e9c88900d358a88740[9]cf4312e7f80000008800052e47c0 [00000.265]
{229}555555569c8e9c88900d358a88740[a]bf4312e7f80000008800052ad0b0 [00000.265]
{230}555555569c8e9c88900d358a88740[b]8f4312e7f80000008800052ea724 [00000.265]

{229}555555569c8e9c88900d358a88740[8]1f4b12e0400800008800052d2d98 [00000.274]
{229}555555569c8e9c88900d358a88740[8]ef4b12e0400800008800052d05b0 [00000.274]
{230}555555569c8e9c88900d358a88740[9]bf4b12e040080000880005296230 [00000.274]

{229}555555569c8e9c88900d358a88740[d]875312e0700800008800052c6970 [00000.280]
{229}555555569c8e9c88900d358a88740[e]b75312e0700800008800052ce1f8 [00000.280]
{231}555555569c8e9c88900d358a88740[f]bf5312e0700800008800052a9d92 [00000.280]

This position counts up in the package group it is in.

zuckschwerdt commented 1 year ago

That would be CTR for LEN:8d MSG:8h ID?8h8h 8h8h VAL?16d CTR?8h 8h8h 8h 8h8h 8h8h 8h8h 8h CRC:8h8h IGNORE:8h format in the BitBench above, right?

zuckschwerdt commented 1 year ago

ah, found it: "AMOUNT" with LEN:8d MSG:8h ID?8h8h 8h8h VAL?16h CTR?8h 8h8h AMOUNT:<32d 32h CRC:8h8h IGNORE:8h

merbanan commented 1 year ago

The ID is correct also: 240234918 -> E51B1A6. It looks like this in the bitbuffer: ID?a6b1 510e. So we just reverse the value and we are done: 0e51b1a6.

zuckschwerdt commented 1 year ago

Ok little endian then ;) LEN:8d MSG:8h ID:<32d ?8h CTR?<32h AMOUNT:<32d 32h CRC:8h8h IGNORE:8h And maybe the "CTR" field also. We need to see a rollover, so more codes please ;) Codes 5c62e6e6 going to 5c62eaf7 need to go to 5c62ffff, and then 5c630000 if the guess is correct (is it maybe a time value?).

merbanan commented 1 year ago

And just as an observation the amount value is 10 less then the observed value.

AMOUNT:0000000255 [00000.265] AMOUNT:0000000264 [00000.274] AMOUNT:0000000270 [00000.280]

vierundvierzig commented 1 year ago

Ok little endian then ;) LEN:8d MSG:8h ID:<32d ?8h CTR?<32h AMOUNT:<32d 32h CRC:8h8h IGNORE:8h And maybe the "CTR" field also. We need to see a rollover, so more codes please ;)

CTR?<32d looks like some kind of timestamp. You can spot 30 seconds between some messages. But then "1549985510" is timestamp for Tue Feb 12 2019 15:31:50 GMT+0000 and it doesn't make sense

merbanan commented 1 year ago

If it is a CC1100 transceiver then you could send a command to the device to update the time in a device. To me the timestamp matches to well for it to not be that. That it is the wrong date doesnt really matter. The date is known by the consumer and the message timestamp delta is of interest. We do get a timestamp from rtl_433 so it is kind of redundant but identifying more fields is always good.

merbanan commented 1 year ago

Anyway this should be enough for a decoder. The decoder should dump the raw buffers for msg types other then 1 and 2. There where a few more possible packets listed in the issue thread.

value at the end of previous month (in liters)
value since 1st day of the month till today (in liters)
warning about magnet field
warning about reverse flow
vierundvierzig commented 1 year ago

So what is next step? Are you going to implement new decoder or I should do some work (I have no idea what)?

merbanan commented 1 year ago

Short term someone should write a decoder. Long term you need to record lots of messages so that we can try to figure out more parameters.

vierundvierzig commented 1 year ago

Ok, I will do my best to record messages. And I will read information via dedicated device for this meters, so we will know what values we are looking for.

PS. I have small radio device for 868MHz, TTGO LoRa OLED. I'm trying to receive those packets via RadioLib library, but no success. Do you know that library? Could you point me what I should set? My settings for now:

  int state = radio.beginFSK();
  state = radio.setFrequency(868.0);
  state = radio.setBitRate(1000);
  state = radio.setFrequencyDeviation(150.0);
  state = radio.setRxBandwidth(250.0);
  state = radio.disableAddressFiltering();
  state = radio.setPreambleLength(4);
  uint8_t syncWord[] = {0xd3, 0x91, 0xd3, 0x91};
  state = radio.setSyncWord(syncWord, 4);
merbanan commented 1 year ago

Are you sure the chip can handle FSK modulation? The settings look fairly sane to me.

zuckschwerdt commented 1 year ago

PS. I have small radio device for 868MHz, TTGO LoRa OLED.

A LoRa radio won't be compatible, right? Is the setBitRate(1000) 1000 bps (typical for LoRa)? We'd need 100 kbps…

matthias-bs commented 1 year ago

The chip is an Semtech SX1276 or HopeRF95W (or compatible) which supports 100 kbps in FSK mode. Receiving data from Bresser Weather Stations based on RadioLib seems to work: https://github.com/matthias-bs/BresserWeatherSensorReceiver

LoRa uses a different modulation.

vierundvierzig commented 1 year ago

Yes, I'm sure the chip can handle FSK modulation, I use it for Open Glider Network which also works on FSK. From specification of SX1276: FSK, GFSK, MSK, GMSK, LoRa and OOK modulation.

From RadioLib docs: setBitRate() Sets FSK bit rate. Allowed values range from 1.2 to 300 kbps. Only available in FSK mode.

matthias-bs commented 1 year ago

If I remember correctly, one important step was to disable CRC filtering: state = radio.setCrcFiltering(false);

In general (and especially for debugging) it is recommended to check the return value (state) after each configuration step to see if the settings were valid.

merbanan commented 1 year ago

Ok, try to create a transmitter with about the same parameters as the Flowis meters. Then you can use rtl_433 to see if the signal looks the same on the receiving end.

vierundvierzig commented 1 year ago

state = radio.setCrcFiltering(false);

Perfect shot! Thank you very much! I have still 5 minutes of TX :)

vierundvierzig commented 1 year ago

Hi, a couple of days decoding and I have new ideas. First of all, packet length is different when meter recorded some kind of alarms. Second, amount represents <24d, not <32d. Next 8d shows Alarm. When there is reverse flow it shows "032", when reverse flow and magnetic field: "160". Next byte is amount in liters of reverse flow. Bytes between ID and Amount shows probably time and something else. Meters has for sure correct date and time. Using ' 8d <16d 8d 8d' for this part, I spotted on midnight that middle part (<16d 8d) counts something like seconds and days. Or it just look like... For now, this is my new BitBench

StKob commented 1 year ago

Are times that you written besides recording times of message being sent? That "<16d" is quite close to seconds from midnight at the beginning. For one at 00:32:03 I'm getting like 00:34:09 but for 09:21:03 its already 10:36:48. But it feels too close for it to be coincidence.

EDIT

Using "2d 5d 9d" instead of "8d 8d" after that "<16d" shows values similar to month and day. That one might be coincidence. It would be great to get data from more days, and months to validate that.

vierundvierzig commented 1 year ago

Inspecting all data collected till today it seems to be a correct findings... And it should be also a year, hour, minute and seconds somewhere ;)

If you use "8d <32d" for this part it looks like timestamps and counts a seconds between readings perfectly correct.

vierundvierzig commented 1 year ago

Solved :) I don't know how to write it on BitBench but this is my idea, i.e:

{249}2aaaad391d3911501a6b1510e8125936c5c7c0100a00e0000a5010003900870 [2023-01-22 09:12:40] (* Note that it is a time of receiving by rtl_433)

Let's take this part: 25 93 6c 5c In binary system: 00100101 10010011 01101100 01011100 Reverse and join: 01011100011011001001001100100101 And split again: 010111 0001 10110 01001 001100 100101 010111: 23 0001: 1 10110: 22 01001: 9 001100: 12 100101: 37

StKob commented 1 year ago

Reverse and join is done by "<32b" but no idea how to split it again and read as decimal. I will ask at bitbench github if there is a way to do this.

StKob commented 1 year ago

Looking at alarms. My guess is its just flipping bits off and on.

For reverse flow its "00100000" and for both flow and magnetic field its "10100000". I bet that for another alarm we would see different bit being on. You can try activating leak alarm and radio module tamper one. Just not both at the same time.

StKob commented 1 year ago

I've got a bit of recording from time where 2 units got mounted in my house. Although its from rtl-sdr from crappy antenna and whole small town is getting equipped with those. recording.txt

merbanan commented 1 year ago

I'll see if I am able to get back to coding this evening.

vierundvierzig commented 1 year ago

CRC is very important. I had situation that a small error gave good result for date, time and reading but changed one number in ID. And readings was assigned to wrong address...

merbanan commented 1 year ago

https://github.com/merbanan/rtl_433/pull/2357

merbanan commented 1 year ago

I'll add the date stuff later. Can I have some more signals ?

StKob commented 1 year ago

I can record few days but there might be a lot garbage in it.

StKob commented 1 year ago

record 03.02.2023.txt