-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Developer Version maciekn
- Loading branch information
Showing
16 changed files
with
2,419 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
Oops, something went wrong.