Initial commit

This commit is contained in:
Nigreon 2025-02-22 23:32:03 +01:00
commit f83dd4f105
36 changed files with 3704 additions and 0 deletions

View file

@ -0,0 +1,150 @@
/*
Transmissions includes an id. Every 60 seconds the sensor transmits 6 packets:
0000 1111 | 0011 0000 | 0101 1100 | 1110 0111 | 0110 0001
iiii iiii | cccc ub?? | tttt tttt | tttt hhhh | hhhh ??nn
- i: identification // changes on battery switch
- c: CRC-4 // CCITT checksum, see below for computation specifics
- u: unknown // (sometimes set at power-on, but not always)
- b: battery low // flag to indicate low battery voltage
- h: Humidity // BCD-encoded, each nibble is one digit, 'A0' means 100%rH
- t: Temperature // in °F as binary number with one decimal place + 90 °F offset
- n: Channel // Channel number 1 - 3
*/
int old_duration = 0;
int new_duration = 0;
unsigned long old_time = 0;
unsigned long new_time = 0;
boolean old_status = LOW;
boolean new_status = LOW;
boolean started = false;
byte input = 2;
uint8_t msg[5];
byte indexBit = 0;
void setup() {
// put your setup code here, to run once:
pinMode(input, INPUT_PULLUP);
Serial.begin(500000);
}
void loop() {
// put your main code here, to run repeatedly:
receive();
}
void receive() {
new_status = digitalRead(input);
if (new_status != old_status) {
new_time = micros();
new_duration = new_time - old_time;
if (!new_status && !started) {
if (durationEquals(old_duration, 7850, 100) && (durationEquals(new_duration, 600, 100)) ) {// __________|"| //that's a start
started = true;
}
}
else if (new_status && started) {//right after rising edge
if (durationEquals(old_duration, 600, 100)) {
if (new_duration < 2700) {// it's a 0
bitWrite(msg[indexBit / 8], 7 - (indexBit % 8), 0);
}
else {// it's a 1
bitWrite(msg[indexBit / 8], 7 - (indexBit % 8), 1);
}
indexBit++;
}
else { // abort if high level duration is not correct
started = false;
indexBit = 0;
}
if (indexBit >= 40) {// stop when 40 bits are received
started = false;
indexBit = 0;
if (infactory_crc_check()) {
decode();
}
else {
Serial.println("CRC Error");
}
}
}
old_time = new_time;
old_duration = new_duration;
}
old_status = new_status;
}
void decode() {
byte iD = msg[0];
bool battery_low = (msg[1] >> 2) & 1;
int temp_raw = (msg[2] << 4) | (msg[3] >> 4);
byte humidity = (msg[3] & 0x0F) * 10 + (msg[4] >> 4); // BCD, 'A0'=100%rH
byte channel = msg[4] & 0x03;
float temp_f = ((float)temp_raw * 0.1 - 122) * 5 / 9.;
Serial.print("iD=");
Serial.print(iD, HEX);
Serial.print("; lo_bat=");
Serial.print(battery_low);
Serial.print("; hum=");
Serial.print(humidity);
Serial.print("; chn=");
Serial.print(channel);
Serial.print("; tmp=");
Serial.println(temp_f);
}
bool durationEquals(int duration1, int duration2, int tolerance) {
if (abs(duration1 - duration2) <= tolerance) return true;
else return false;
}
void printHex(byte b) {
if (b < 0x10) Serial.print("0");
Serial.print(b, HEX);
}
uint8_t crc4(uint8_t const message[], unsigned nBytes, uint8_t polynomial, uint8_t init)
{
unsigned remainder = init << 4; // LSBs are unused
unsigned poly = polynomial << 4;
unsigned bit;
while (nBytes--) {
remainder ^= *message++;
for (bit = 0; bit < 8; bit++) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ poly;
} else {
remainder = (remainder << 1);
}
}
}
return remainder >> 4 & 0x0f; // discard the LSBs
}
bool infactory_crc_check() {
uint8_t msg_crc, crc;
msg_crc = msg[1] >> 4;
// for CRC computation, channel bits are at the CRC position(!)
msg[1] = (msg[1] & 0x0F) | (msg[4] & 0x0F) << 4;
// crc4() only works with full bytes
crc = crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
crc ^= msg[4] >> 4; // last nibble is only XORed
return (crc == msg_crc);
}

View file

@ -0,0 +1,116 @@
#define PIN_TX 4
uint8_t msg[5];
uint8_t id = 0x2C;
uint8_t channel = 0x01;
bool batteryOK = 0;// 0 means OK
uint8_t humidity = 69;
float temperature = 1.;
void setup() {
Serial.begin(9600);
pinMode(PIN_TX, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
temperature += 1.;
if (temperature >= 35.) temperature = 1.;
buildMsg();
sendRF();
delay(10000);
}
void buildMsg(){
// put your setup code here, to run once:
msg[0] = id;
msg[4] = channel + ((humidity%10) << 4 );
msg[3] = humidity/10;
int binTemp = ((temperature * 9./5) + 32 + 90)*10;
msg[3] += (binTemp & 0x0F) << 4;
msg[2] = binTemp >> 4;
msg[1] = batteryOK << 2;
msg[1] = (msg[1] & 0x0F) | (msg[4] & 0x0F) << 4;
// crc4() only works with full bytes
uint8_t crc = crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
crc ^= msg[4] >> 4; // last nibble is only XORed
msg[1] = (msg[1] & 0x0F) | (crc & 0x0F) << 4;
for (int i=0; i<=4; i++){
Serial.print(msg[i],HEX);
Serial.print(" ");
}
}
uint8_t crc4(uint8_t const message[], unsigned nBytes, uint8_t polynomial, uint8_t init)
{
unsigned remainder = init << 4; // LSBs are unused
unsigned poly = polynomial << 4;
unsigned bit;
while (nBytes--) {
remainder ^= *message++;
for (bit = 0; bit < 8; bit++) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ poly;
} else {
remainder = (remainder << 1);
}
}
}
return remainder >> 4 & 0x0f; // discard the LSBs
}
void sendRF()
{
/*low long 4000
low short 1800
high short 700
*/
for (int n=0; n<6; n++)
{
for (int i=0; i<10; i++){
digitalWrite(PIN_TX, !(i%2));
delayMicroseconds(1000);
}
delayMicroseconds(7000);
for (int i = 0; i<5; i++) {
for (int b = 7; b>=0; b--) {
digitalWrite(PIN_TX, HIGH);
delayMicroseconds(700);
digitalWrite(PIN_TX, LOW);
if (bitRead(msg[i], b)){
delayMicroseconds(4000);
}
else{
delayMicroseconds(1800);
}
}
}
digitalWrite(PIN_TX, HIGH);
delayMicroseconds(1000);
digitalWrite(PIN_TX, LOW);
delayMicroseconds(16000);
}
}