forked from joysfera/arduino-water-temp-receiver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWaterTempReceiver.cpp
166 lines (143 loc) · 4.13 KB
/
WaterTempReceiver.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
* Water Temperature Receiver v1.1
*
* This library receives and decodes data sent by
* remote water sensor KW9043, Hyundai WSC (Hyundai WSC 1925) and compatible ones.
*
* Copyright 2013 by Petr Stehlik http://pstehlik.cz/
v1.1
* Added support to read negative temperatures by Radius
* Idea of the communication protocol and timing based on
* reverse-engineering of Abdullah Tahiri's RemoteTransmitter
*
* License: GPLv3. See LICENSE.md
*/
#include <WaterTempReceiver.h>
short int WaterTempReceiver::interrupt;
WaterTempReceiverCallback WaterTempReceiver::callback;
byte WaterTempReceiver::interruptPin;
bool WaterTempReceiver::enabled;
unsigned long WaterTempReceiver::lastChange;
bool WaterTempReceiver::preamble;
bool WaterTempReceiver::space;
byte WaterTempReceiver::bits;
bool WaterTempReceiver::arr[28];
byte WaterTempReceiver::last_id;
byte WaterTempReceiver::last_chan;
int WaterTempReceiver::last_temp;
unsigned long WaterTempReceiver::last_milistamp;
void WaterTempReceiver::init(short int _interrupt, WaterTempReceiverCallback _callback)
{
interrupt = _interrupt;
callback = _callback;
interruptPin = (interrupt == 0) ? 2 : 3; // TODO: find a conversion function for this
pinMode(interruptPin, INPUT_PULLUP);
enable();
if (interrupt >= 0)
attachInterrupt(interrupt, interruptHandler, CHANGE);
}
void WaterTempReceiver::deinit()
{
disable();
if (interrupt >= 0)
detachInterrupt(interrupt);
}
void WaterTempReceiver::enable()
{
lastChange = micros();
bits = 0;
preamble = space = false;
enabled = true;
}
void WaterTempReceiver::disable()
{
enabled = false;
}
bool WaterTempReceiver::isImpuls(int duration)
{
return (abs(duration) <= RWR_TOLERANCE);
}
void WaterTempReceiver::interruptHandler()
{
if (!enabled) return;
unsigned long currentTime = micros();
unsigned duration = currentTime - lastChange;
lastChange = currentTime;
boolean state = digitalRead(interruptPin);
if (!state) { // goes from HIGH to LOW
space = isImpuls(duration - 500);
}
else if (space) { // goes from LOW to HIGH
if (!preamble) {
preamble = isImpuls(duration - 9500);
bits = 0;
}
else {
boolean low = isImpuls(duration - 2000);
boolean high = !low && isImpuls(duration - 4500);
if (low != high) {
arr[bits++] = high;
if (bits == 28) {
decodeTemp();
bits = 0;
preamble = false;
}
}
else {
preamble = false;
}
}
space = false;
}
}
int WaterTempReceiver::readBits(byte start, byte count)
{
int val = 0;
for(byte i = start; i < start + count; i++) {
val <<= 1;
val |= arr[i];
}
return val;
}
bool WaterTempReceiver::checkSum()
{
byte checksum = readBits(0, 4);
byte chk = 0;
for(byte i=1; i<7; i++)
chk += readBits(i*4, 4);
chk--;
return (checksum == (chk & 0x0f));
}
void WaterTempReceiver::decodeTemp()
{
// check control sum
if (!checkSum()) {
// Serial.println("Checksum failed.");
return;
}
// decode to temporary variables and compare with internal struct
byte id = readBits(4, 8);
byte temp_sign = readBits(12, 4);
int temp = readBits(16, 8);
byte chan = readBits(24, 2);
boolean batt = arr[26]; //BAT OK = 1
boolean beep = arr[27]; //BEEP = 1
// = 1111 = freezing, let's do two complement
if (temp_sign == B1111)
{
temp = temp ^ B11111111;
temp = -temp - 1;
}
// if it's the same data and last timestamp is less than 1 second ago then ignore it
if ((millis() - last_milistamp) < 1000 && id == last_id && temp == last_temp && chan == last_chan) {
// Serial.println("Received same packet again");
return;
}
// store temporary variables to internal struct and mark it with current timestamp (millis)
last_id = id;
last_temp = temp;
last_chan = chan;
last_milistamp = millis();
// call user callback with data
(callback)(id, temp, chan, batt, beep);
}