-
-
Save RouquinBlanc/5cb6ff88cd02e68d48ea to your computer and use it in GitHub Desktop.
Based on: | |
- original work from found on this place: | |
http://www.connectingstuff.net/blog/encodage-protocoles-oregon-scientific-sur-arduino/ | |
- Oregon Protocol description: | |
http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf | |
- BTHR918N frame description from this site: | |
http://syno.haeflinger.com/index.php/Domotique#BTHR918N | |
I was able to get a correct signal emitted from a simple RF433MHz transmitter plugged on an Arduino nano, | |
decoded by the RFXCOM Rfxtrx433e module, and then correctly displayed on Domoticz. |
/* | |
* connectingStuff, Oregon Scientific v2.1 Emitter | |
* http://www.connectingstuff.net/blog/encodage-protocoles-oregon-scientific-sur-arduino/ | |
* | |
* Copyright (C) 2013 olivier.lebrun@gmail.com | |
* Modified by Jonathan Martin <therouquinblanc@gmail.com>, August 2015 | |
* | |
* This program is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU General Public License | |
* as published by the Free Software Foundation; either version 2 | |
* of the License, or (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
*/ | |
#define MODE_0 0 // Temperature only [THN132N] | |
#define MODE_1 1 // Temperature + Humidity [THGR2228N] | |
#define MODE_2 2 // Temperature + Humidity + Baro() [BTHR918N] | |
#define MODE MODE_2 | |
const byte TX_PIN = 6; | |
const unsigned long TIME = 512; | |
const unsigned long TWOTIME = TIME*2; | |
#define SEND_HIGH() digitalWrite(TX_PIN, HIGH) | |
#define SEND_LOW() digitalWrite(TX_PIN, LOW) | |
// Buffer for Oregon message | |
#if MODE == MODE_0 | |
byte OregonMessageBuffer[8]; | |
#elif MODE == MODE_1 | |
byte OregonMessageBuffer[9]; | |
#elif MODE == MODE_2 | |
byte OregonMessageBuffer[11]; | |
#else | |
#error mode unknown | |
#endif | |
/** | |
* \brief Send logical "0" over RF | |
* \details azero bit be represented by an off-to-on transition | |
* \ of the RF signal at the middle of a clock period. | |
* \ Remenber, the Oregon v2.1 protocol add an inverted bit first | |
*/ | |
inline void sendZero(void) | |
{ | |
SEND_HIGH(); | |
delayMicroseconds(TIME); | |
SEND_LOW(); | |
delayMicroseconds(TWOTIME); | |
SEND_HIGH(); | |
delayMicroseconds(TIME); | |
} | |
/** | |
* \brief Send logical "1" over RF | |
* \details a one bit be represented by an on-to-off transition | |
* \ of the RF signal at the middle of a clock period. | |
* \ Remenber, the Oregon v2.1 protocol add an inverted bit first | |
*/ | |
inline void sendOne(void) | |
{ | |
SEND_LOW(); | |
delayMicroseconds(TIME); | |
SEND_HIGH(); | |
delayMicroseconds(TWOTIME); | |
SEND_LOW(); | |
delayMicroseconds(TIME); | |
} | |
/** | |
* Send a bits quarter (4 bits = MSB from 8 bits value) over RF | |
* | |
* @param data Source data to process and sent | |
*/ | |
/** | |
* \brief Send a bits quarter (4 bits = MSB from 8 bits value) over RF | |
* \param data Data to send | |
*/ | |
inline void sendQuarterMSB(const byte data) | |
{ | |
(bitRead(data, 4)) ? sendOne() : sendZero(); | |
(bitRead(data, 5)) ? sendOne() : sendZero(); | |
(bitRead(data, 6)) ? sendOne() : sendZero(); | |
(bitRead(data, 7)) ? sendOne() : sendZero(); | |
} | |
/** | |
* \brief Send a bits quarter (4 bits = LSB from 8 bits value) over RF | |
* \param data Data to send | |
*/ | |
inline void sendQuarterLSB(const byte data) | |
{ | |
(bitRead(data, 0)) ? sendOne() : sendZero(); | |
(bitRead(data, 1)) ? sendOne() : sendZero(); | |
(bitRead(data, 2)) ? sendOne() : sendZero(); | |
(bitRead(data, 3)) ? sendOne() : sendZero(); | |
} | |
/******************************************************************/ | |
/******************************************************************/ | |
/******************************************************************/ | |
/** | |
* \brief Send a buffer over RF | |
* \param data Data to send | |
* \param size size of data to send | |
*/ | |
void sendData(byte *data, byte size) | |
{ | |
for(byte i = 0; i < size; ++i) | |
{ | |
sendQuarterLSB(data[i]); | |
sendQuarterMSB(data[i]); | |
} | |
} | |
/** | |
* \brief Send an Oregon message | |
* \param data The Oregon message | |
*/ | |
void sendOregon(byte *data, byte size) | |
{ | |
sendPreamble(); | |
//sendSync(); | |
sendData(data, size); | |
sendPostamble(); | |
} | |
/** | |
* \brief Send preamble | |
* \details The preamble consists of 16 "1" bits | |
*/ | |
inline void sendPreamble(void) | |
{ | |
byte PREAMBLE[]={0xFF,0xFF}; | |
sendData(PREAMBLE, 2); | |
} | |
/** | |
* \brief Send postamble | |
* \details The postamble consists of 8 "0" bits | |
*/ | |
inline void sendPostamble(void) | |
{ | |
#if MODE == MODE_0 | |
sendQuarterLSB(0x00); | |
#else | |
byte POSTAMBLE[]={0x00}; | |
sendData(POSTAMBLE, 1); | |
#endif | |
} | |
/** | |
* \brief Send sync nibble | |
* \details The sync is 0xA. It is not use in this version since the sync nibble | |
* \ is include in the Oregon message to send. | |
*/ | |
inline void sendSync(void) | |
{ | |
sendQuarterLSB(0xA); | |
} | |
/******************************************************************/ | |
/******************************************************************/ | |
/******************************************************************/ | |
/** | |
* \brief Set the sensor type | |
* \param data Oregon message | |
* \param type Sensor type | |
*/ | |
inline void setType(byte *data, byte* type) | |
{ | |
data[0] = type[0]; | |
data[1] = type[1]; | |
} | |
/** | |
* \brief Set the sensor channel | |
* \param data Oregon message | |
* \param channel Sensor channel (0x10, 0x20, 0x30) | |
*/ | |
inline void setChannel(byte *data, byte channel) | |
{ | |
data[2] = channel; | |
} | |
/** | |
* \brief Set the sensor ID | |
* \param data Oregon message | |
* \param ID Sensor unique ID | |
*/ | |
inline void setId(byte *data, byte ID) | |
{ | |
data[3] = ID; | |
} | |
/** | |
* \brief Set the sensor battery level | |
* \param data Oregon message | |
* \param level Battery level (0 = low, 1 = high) | |
*/ | |
void setBatteryLevel(byte *data, byte level) | |
{ | |
if(!level) data[4] = 0x0C; | |
else data[4] = 0x00; | |
} | |
/** | |
* \brief Set the sensor temperature | |
* \param data Oregon message | |
* \param temp the temperature | |
*/ | |
void setTemperature(byte *data, float temp) | |
{ | |
// Set temperature sign | |
if(temp < 0) | |
{ | |
data[6] = 0x08; | |
temp *= -1; | |
} | |
else | |
{ | |
data[6] = 0x00; | |
} | |
// Determine decimal and float part | |
int tempInt = (int)temp; | |
int td = (int)(tempInt / 10); | |
int tf = (int)round((float)((float)tempInt/10 - (float)td) * 10); | |
int tempFloat = (int)round((float)(temp - (float)tempInt) * 10); | |
// Set temperature decimal part | |
data[5] = (td << 4); | |
data[5] |= tf; | |
// Set temperature float part | |
data[4] |= (tempFloat << 4); | |
} | |
/** | |
* \brief Set the sensor humidity | |
* \param data Oregon message | |
* \param hum the humidity | |
*/ | |
void setHumidity(byte* data, byte hum) | |
{ | |
data[7] = (hum/10); | |
data[6] |= (hum - data[7]*10) << 4; | |
} | |
/** | |
* \brief Set the sensor temperature | |
* \param data Oregon message | |
* \param temp the temperature | |
*/ | |
void setPressure(byte *data, float pres) | |
{ | |
if ((pres > 850) && (pres < 1100)) { | |
data[8] = (int)round(pres) - 856; | |
data[9] = 0xC0; | |
} | |
} | |
/** | |
* \brief Sum data for checksum | |
* \param count number of bit to sum | |
* \param data Oregon message | |
*/ | |
int Sum(byte count, const byte* data) | |
{ | |
int s = 0; | |
for(byte i = 0; i<count;i++) | |
{ | |
s += (data[i]&0xF0) >> 4; | |
s += (data[i]&0xF); | |
} | |
if(int(count) != count) | |
s += (data[count]&0xF0) >> 4; | |
return s; | |
} | |
/** | |
* \brief Calculate checksum | |
* \param data Oregon message | |
*/ | |
void calculateAndSetChecksum(byte* data) | |
{ | |
#if MODE == MODE_0 | |
int s = ((Sum(6, data) + (data[6]&0xF) - 0xa) & 0xff); | |
data[6] |= (s&0x0F) << 4; data[7] = (s&0xF0) >> 4; | |
#elif MODE == MODE_1 | |
data[8] = ((Sum(8, data) - 0xa) & 0xFF); | |
#else | |
data[10] = ((Sum(10, data) - 0xa) & 0xFF); | |
#endif | |
} | |
/******************************************************************/ | |
/******************************************************************/ | |
/******************************************************************/ | |
void setup() | |
{ | |
pinMode(TX_PIN, OUTPUT); | |
Serial.begin(9600); | |
Serial.println("\n[Oregon V2.1 encoder]"); | |
SEND_LOW(); | |
#if MODE == MODE_0 | |
// Create the Oregon message for a temperature only sensor (THN132N) | |
byte ID[] = {0xEA,0x4C}; | |
#elif MODE == MODE_1 | |
// Create the Oregon message for a temperature/humidity sensor (THGR2228N) | |
byte ID[] = {0x1A,0x2D}; | |
#else | |
// Create the Oregon message for a temperature/humidity/barometer sensor (BTHR918N) | |
byte ID[] = {0x5A, 0x6D}; | |
#endif | |
setType(OregonMessageBuffer, ID); | |
setChannel(OregonMessageBuffer, 0x20); | |
setId(OregonMessageBuffer, 0xCB); | |
} | |
void loop() | |
{ | |
// Get Temperature, humidity and battery level from sensors | |
// (ie: 1wire DS18B20 for température, ...) | |
setBatteryLevel(OregonMessageBuffer, 1); // 0 : low, 1 : high | |
setTemperature(OregonMessageBuffer, 11.2); | |
#if MODE != MODE_0 | |
// Set Humidity | |
setHumidity(OregonMessageBuffer, 52); | |
#endif | |
#if MODE == MODE_2 | |
// Set Pressure | |
setPressure(OregonMessageBuffer, 1013); | |
#endif | |
// Calculate the checksum | |
calculateAndSetChecksum(OregonMessageBuffer); | |
// Show the Oregon Message | |
Serial.println("Oregon -> "); | |
for (byte i = 0; i < sizeof(OregonMessageBuffer); ++i) { | |
Serial.print(OregonMessageBuffer[i] >> 4, HEX); | |
Serial.print(OregonMessageBuffer[i] & 0x0F, HEX); | |
} | |
Serial.println(); | |
// Send the Message over RF | |
sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer)); | |
// Send a "pause" | |
SEND_LOW(); | |
delayMicroseconds(TWOTIME*8); | |
// Send a copie of the first message. The v2.1 protocol send the | |
// message two time | |
sendOregon(OregonMessageBuffer, sizeof(OregonMessageBuffer)); | |
// Wait for 30 seconds before send a new message | |
SEND_LOW(); | |
delay(30000); | |
} |
ciao, many thanks for your work !
I've tried this code with different arduino's board, a nano and uno with a simple tx on 433,920 simulating a common THGR228N.
the problem is that another arduino can receive and decode the simulated transmission but no oregon bases are capable to receive it .
what I wrong ?
I fear going crazy ...
ciao, many thanks for your work !
I've tried this code with different arduino's board, a nano and uno with a simple tx on 433,920 simulating a common THGR228N. the problem is that another arduino can receive and decode the simulated transmission but no oregon bases are capable to receive it . what I wrong ? I fear going crazy ...
Did you solve?
Sorry, this is too old in my memory I don't use this anymore... If you find a solution, please post here for reference!
I used this code on my arduino Nano to send it to my Raspberry with Pilight installed
This works with my pilight compiled with v7_oregon and test_dev branch from https://github.com/wo-rasp/pilight/tree/test_dev
But the pressure gave me strange readings so i altered the setPressure since it swaps bytes
( for instance 5A6D1234567890 becomes 5A6D2143658709 )
With the code below it works fine:
void setPressure(byte *data, float pres)
{
data[8] = (((int)round(pres) & 0x0F00) >> 4 | ((int)round(pres) & 0xF000)>>12 );
data[9] = (((int)round(pres) & 0x000F) << 4 | ((int)round(pres) & 0x00F0)>>4 );
}