Skip to content

Commit

Permalink
water-meter-izar version
Browse files Browse the repository at this point in the history
Developer Version maciekn
  • Loading branch information
zibous committed Apr 19, 2023
1 parent 948dec0 commit 36946bb
Show file tree
Hide file tree
Showing 16 changed files with 2,419 additions and 0 deletions.
94 changes: 94 additions & 0 deletions esphome/custom_components/izar-wmbus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Izar water meter reader (ESP8266 and ESP32 -based)
The idea behind the project is to read Izar water meter current consumption

Implementation is naive, and hardcoded in many places. It was meant to be simple ;)

## Required components
- NodeMCU (however any ESP8266-based device should work fine)
- CC1101 module (ideally with an antena tuned to 868MHz *)

_Note_: While CC1101 chip is versatile and may by configured programatically to use different frequency, some PCB components has to be selected for better performance. Therefore, please pay attention to get the right one.More info here: https://wiki.fhem.de/wiki/Selbstbau_CUL

I was able to use CC1101 board tuned for 433MHz correctly, though ;)

## Usage

```
IzarWmbus reader;
void setup() {
//somewhere in the setup
reader.init(0);
}
IzarResultData data;
void loop() {
FetchResult result = reader.fetchPacket(&data);
if (result == FETCH_SUCCESSFUL) {
// we have new package!
}
}
```


## Wiring
### ESP8266
```
CC1101 -> NodeMCU
==================
SCK -> D5
MISO -> D6
MOSI -> D7
CSN -> D8
VCC -> 3V
GND -> GND
```

### ESP32-CAM
My main challenge with wiring ESP32-CAM was use of the default SPI connection by camera module, so I had to divert to other pin set
```
CC1101 -> ESP32(left side)
============================
5V
GND
MISO -> GPIO12
MOSI -> GPIO13
CSN -> GPIO15
SCK -> GPIO14
GPIO2
GPIO4
(right side)
VCC -> 3V3
GDN -> GND
```

More details about wiring in library this tool is using for connecting with CC1101: https://github.com/LSatan/SmartRC-CC1101-Driver-Lib

### CC1101 868Mhz pinout
(connectors on the left, ANT on the right)

```
VCC -----------------
GND | |
MOSI | |
SCK | CC1101 | GND
MISO | | ANT
GDO2 | | GND
GDO0 | crystal |
CSN |_______________-
```

## Building and usage
The library is based on PlatformIO and is build through PlatformIO's toolchain.

## Related materials:
- Application note on using CC1101 with Wirless MBUS: https://www.ti.com/lit/an/swra234a/swra234a.pdf
- CULFW source code: https://github.com/heliflieger/a-culfw/
- App filtering WMBUS packets from RTL: https://github.com/xaelsouth/rtl-wmbus
- Almighty WMBUS meters decoders library: https://github.com/weetmuts/wmbusmeters
107 changes: 107 additions & 0 deletions esphome/custom_components/izar-wmbus/izar_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "izar_utils.h"

#include <Arduino.h>

#define CRC_POLYNOM 0x3D65


const uint8_t decoder[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0x03,0xFF,0x01,0x02,0xFF,
0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0x00,0xFF,
0xFF,0x05,0x06,0xFF,0x04,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0x0B,0xFF,0x09,0x0A,0xFF,
0xFF,0x0F,0xFF,0xFF,0x08,0xFF,0xFF,0xFF,
0xFF,0x0D,0x0E,0xFF,0x0C,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

uint32_t uintFromBytes(uint8_t* data) {
uint32_t result = data[0] << 24;
result += data[1] << 16;
result += data[2] << 8;
result += data[3];
return result;
}

uint32_t uintFromBytesLittleEndian(uint8_t* data) {
uint32_t result = data[3] << 24;
result += data[2] << 16;
result += data[1] << 8;
result += data[0];
return result;
}

uint16_t uint16FromBytes(uint8_t* data) {
uint16_t result = data[0] << 8;
result += data[1];
return result;
}

uint32_t hashShiftKey(uint32_t key) {
for (uint8_t i = 0; i < 8; i++) {
uint8_t bit = GET_BIT(key, 1) ^ GET_BIT(key, 2) ^ GET_BIT(key, 11) ^
GET_BIT(key, 31);
key <<= 1;
key |= bit;
}
return key;
}

uint8_t decode3of6Single(uint8_t* encoded, uint8_t* decoded) {
uint8_t data[4];

data[0] = decoder[encoded[2] & 0x3F];
data[1] = decoder[((encoded[2] & 0xC0) >> 6) | ((encoded[1] & 0x0F) << 2)];
data[2] = decoder[((encoded[1] & 0xF0) >> 4) | ((encoded[0] & 0x03) << 4)];
data[3] = decoder[((encoded[0] & 0xFC) >> 2)];

for (uint8_t i = 0; i < 4; i++) {
if (data[i] == 0xFF) {
return -1;
}
}

// - Shift the encoded values into a byte buffer -
decoded[0] = (data[3] << 4) | (data[2]);
decoded[1] = (data[1] << 4) | (data[0]);

return 0;
}

uint8_t decrypt(uint8_t* encoded, uint8_t len, uint8_t* decoded) {
if (len < 15) {
return 0;
}

uint32_t key = 0xdfd109e8;
key ^= uintFromBytes(encoded + 2);
key ^= uintFromBytes(encoded + 6);
key ^= uintFromBytes(encoded + 10);

const uint8_t size = len - 15;
for (uint8_t i = 0; i < size; i++) {
key = hashShiftKey(key);
decoded[i] = encoded[i + 15] ^ (key & 0xFF);
}

if (decoded[0] != 0x4B) {
return 0;
}

return size;
}

uint16_t crc16(uint16_t crcVal, uint8_t dataByte) {
for (int i = 0; i < 8; i++) {
if (((crcVal & 0x8000) >> 8) ^ (dataByte & 0x80)) {
crcVal = (crcVal << 1) ^ CRC_POLYNOM;
} else {
crcVal = (crcVal << 1);
}

dataByte <<= 1;
}

return crcVal;
}
16 changes: 16 additions & 0 deletions esphome/custom_components/izar-wmbus/izar_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef IZAR_UTILS
#define IZAR_UTILS

#include <Arduino.h>

#define GET_BIT(var, pos) ((var >> pos) & 0x01)

uint32_t uintFromBytes(uint8_t* data);
uint32_t uintFromBytesLittleEndian(uint8_t* data);
uint16_t uint16FromBytes(uint8_t* data);
uint8_t decrypt(uint8_t* encoded, uint8_t len, uint8_t* decoded);
uint8_t decode3of6Single(uint8_t* encoded, uint8_t* decoded);
uint16_t crc16(uint16_t crcVal, uint8_t dataByte);

#endif

Loading

0 comments on commit 36946bb

Please sign in to comment.