Initial commit
This commit is contained in:
commit
f83dd4f105
|
@ -0,0 +1 @@
|
||||||
|
https://docs.arduino.cc/hardware/nano/
|
Binary file not shown.
|
@ -0,0 +1,101 @@
|
||||||
|
#include "NexusTX.h"
|
||||||
|
|
||||||
|
NexusTX::NexusTX(byte tr_pin)
|
||||||
|
{
|
||||||
|
SendBuffer = new bool[buffer_size];
|
||||||
|
TX_PIN = tr_pin;
|
||||||
|
pinMode(TX_PIN, OUTPUT);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
SendBuffer[9] = 0;
|
||||||
|
SendBuffer[24] = 1;
|
||||||
|
SendBuffer[25] = 1;
|
||||||
|
SendBuffer[26] = 1;
|
||||||
|
SendBuffer[27] = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NexusTX::tx_bit(bool b)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(PULSE_HIGH);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
if (b == true)
|
||||||
|
delayMicroseconds(PULSE_ONE);
|
||||||
|
else
|
||||||
|
delayMicroseconds(PULSE_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::setBatteryFlag(bool level)
|
||||||
|
{
|
||||||
|
SendBuffer[8] = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::setHumidity(int h)
|
||||||
|
{
|
||||||
|
uint8_t h8 = (uint8_t)h;
|
||||||
|
for (idx = 0; idx <= 7; idx++)
|
||||||
|
{
|
||||||
|
SendBuffer[35 - idx] = (h8 >> idx) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::setChannel(byte dev_ch)
|
||||||
|
{
|
||||||
|
SendBuffer[10] = dev_ch & 0x2;
|
||||||
|
SendBuffer[11] = dev_ch & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::setId(byte dev_id)
|
||||||
|
{
|
||||||
|
int array_idx = 0;
|
||||||
|
for (idx = 7; idx >= 0; idx--)
|
||||||
|
{
|
||||||
|
SendBuffer[array_idx++] = dev_id & (0x1 << idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::setTemperature(float t)
|
||||||
|
{
|
||||||
|
int16_t t12 = t * 10.0f;
|
||||||
|
for (idx = 0; idx <= 11; idx++)
|
||||||
|
{
|
||||||
|
SendBuffer[23 - idx] = (t12 >> idx) & 0x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::SendNexus()
|
||||||
|
{
|
||||||
|
for (int i=0; i <buffer_size; i++)
|
||||||
|
{
|
||||||
|
tx_bit(SendBuffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NexusTX::SendPacket()
|
||||||
|
{
|
||||||
|
for (idx = 1; idx < repeat; idx++)
|
||||||
|
{
|
||||||
|
SendNexus();
|
||||||
|
if (idx + 1 == repeat) {break;} // do not send sync after last TX
|
||||||
|
// sync bit
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(PULSE_HIGH);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
delayMicroseconds(PULSE_SYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool NexusTX::transmit()
|
||||||
|
{
|
||||||
|
if (millis() >= time_marker_send && send_time)
|
||||||
|
{
|
||||||
|
time_marker_send = millis() + send_time;
|
||||||
|
SendPacket();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifndef NexusTX_h
|
||||||
|
#define NexusTX_h
|
||||||
|
|
||||||
|
#define PULSE_HIGH 500 /* 500 us */
|
||||||
|
#define PULSE_ZERO 1000 /* 1000 us */
|
||||||
|
#define PULSE_ONE 2000 /* 2000 us */
|
||||||
|
#define PULSE_SYNC 4000 /* 4000 us */
|
||||||
|
|
||||||
|
// Time between two TX = 56.75 seconds
|
||||||
|
#define TX_INTERVAL 56750
|
||||||
|
|
||||||
|
// Bitstream repetition (this device sends the information 10 times)
|
||||||
|
#define repeat 12
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class NexusTX
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool* SendBuffer;
|
||||||
|
int buffer_size=36;
|
||||||
|
int tx_interval = TX_INTERVAL;
|
||||||
|
NexusTX(byte);
|
||||||
|
void setChannel(byte);
|
||||||
|
void setId(byte);
|
||||||
|
void setBatteryFlag(bool);
|
||||||
|
void setTemperature(float);
|
||||||
|
void setHumidity(int);
|
||||||
|
bool transmit();
|
||||||
|
void SendPacket();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void tx_bit(bool);
|
||||||
|
byte TX_PIN;
|
||||||
|
int idx = 0;
|
||||||
|
void SendNexus();
|
||||||
|
unsigned long time_marker_send = 0;
|
||||||
|
unsigned long send_time = TX_INTERVAL;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,901 @@
|
||||||
|
#include "Oregon_TM.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This file is part of the Arduino OREGON_NR library.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Sergey Zawislak
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Этот файл - часть библиотеки OREGON_NR
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Сергей Зависляк
|
||||||
|
//
|
||||||
|
// Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации
|
||||||
|
// (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений,
|
||||||
|
// включая неограниченное право на использование, копирование, изменение, слияние, публикацию, распространение, сублицензирование
|
||||||
|
// и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:
|
||||||
|
//
|
||||||
|
// Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения.
|
||||||
|
//
|
||||||
|
// ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
|
||||||
|
// ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ
|
||||||
|
// НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ,
|
||||||
|
// ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Конструктор
|
||||||
|
|
||||||
|
Oregon_TM::Oregon_TM(byte tr_pin, int buf_size)
|
||||||
|
{
|
||||||
|
max_buffer_size = (int)(buf_size / 2) + 2;
|
||||||
|
SendBuffer = new byte[max_buffer_size + 2];
|
||||||
|
TX_PIN = tr_pin;
|
||||||
|
pinMode(TX_PIN, OUTPUT);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Oregon_TM::Oregon_TM(byte tr_pin)
|
||||||
|
{
|
||||||
|
SendBuffer = new byte[max_buffer_size + 2];
|
||||||
|
TX_PIN = tr_pin;
|
||||||
|
pinMode(TX_PIN, OUTPUT);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Oregon_TM::Oregon_TM(void)
|
||||||
|
{
|
||||||
|
SendBuffer = new byte[max_buffer_size + 2];
|
||||||
|
pinMode(TX_PIN, OUTPUT);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Функции передатчика////////////////////////////////////////////////////////////////////////////
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::sendZero(void)
|
||||||
|
{
|
||||||
|
if (protocol == 2) {
|
||||||
|
while (time_marker + TR_TIME * 4 >= micros());
|
||||||
|
time_marker += TR_TIME * 4;
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(TR_TIME - PULSE_SHORTEN_2);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
delayMicroseconds(TWOTR_TIME + PULSE_SHORTEN_2);
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
}
|
||||||
|
if (protocol == 3)
|
||||||
|
{
|
||||||
|
if (prevstate) while (time_marker + TWOTR_TIME - PULSE_SHORTEN_3 >= micros());
|
||||||
|
else while (time_marker + TWOTR_TIME >= micros());
|
||||||
|
|
||||||
|
time_marker += TWOTR_TIME;
|
||||||
|
|
||||||
|
if (prevbit && prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
prevstate = 0;
|
||||||
|
prevbit = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prevbit && !prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(TWOTR_TIME);
|
||||||
|
prevstate = 1;
|
||||||
|
prevbit = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!prevbit && prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
delayMicroseconds(TR_TIME);
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
prevbit = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!prevbit && !prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(TR_TIME);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
prevbit = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendOne(void)
|
||||||
|
{
|
||||||
|
if (protocol == 2) {
|
||||||
|
while (time_marker + TR_TIME * 4 - PULSE_SHORTEN_2 >= micros());
|
||||||
|
time_marker += TR_TIME * 4;
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
delayMicroseconds(TR_TIME + PULSE_SHORTEN_2);
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(TWOTR_TIME - PULSE_SHORTEN_2);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protocol == 3)
|
||||||
|
{
|
||||||
|
if (prevstate) while (time_marker + TWOTR_TIME - PULSE_SHORTEN_3 >= micros());
|
||||||
|
else while (time_marker + TWOTR_TIME >= micros());
|
||||||
|
time_marker += TWOTR_TIME;
|
||||||
|
|
||||||
|
if (!prevbit && prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
prevstate = 0;
|
||||||
|
prevbit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!prevbit && !prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
prevstate = 1;
|
||||||
|
prevbit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prevbit && prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
delayMicroseconds(TR_TIME);
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
prevbit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prevbit && !prevstate)
|
||||||
|
{
|
||||||
|
digitalWrite(TX_PIN, HIGH);
|
||||||
|
delayMicroseconds(TR_TIME);
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
prevbit = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendMSB(byte data)
|
||||||
|
{
|
||||||
|
(bitRead(data, 4)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 5)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 6)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 7)) ? sendOne() : sendZero();
|
||||||
|
if (protocol == 2) time_marker += timing_corrector2; //Поправка на разницу тактовых частот 1024.07Гц и 1024.60Гц
|
||||||
|
if (protocol == 3) time_marker += timing_corrector3;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendLSB(byte data)
|
||||||
|
{
|
||||||
|
(bitRead(data, 0)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 1)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 2)) ? sendOne() : sendZero();
|
||||||
|
(bitRead(data, 3)) ? sendOne() : sendZero();
|
||||||
|
if (protocol == 2) time_marker += timing_corrector2; //Поправка на разницу тактовых частот 1024.07Гц и 1024.60Гц
|
||||||
|
if (protocol == 3) time_marker += timing_corrector3;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendData()
|
||||||
|
{
|
||||||
|
int q = 0;
|
||||||
|
for (byte i = 0; i < max_buffer_size; i++)
|
||||||
|
{
|
||||||
|
sendMSB(SendBuffer[i]);
|
||||||
|
q++;
|
||||||
|
if (q >= buffer_size) break;
|
||||||
|
sendLSB(SendBuffer[i]);
|
||||||
|
q++;
|
||||||
|
if (q >= buffer_size) break;
|
||||||
|
if (protocol == 2) time_marker += 4; //Поправка на разницу тактовых частот 1024.07Гц и 1024.60Гц
|
||||||
|
//if (protocol == 3) time_marker += 4;
|
||||||
|
//Поправка на разницу тактовых частот 1024.07Гц и 1024Гц
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendOregon()
|
||||||
|
{
|
||||||
|
time_marker = micros();
|
||||||
|
sendPreamble();
|
||||||
|
sendLSB(0xA);
|
||||||
|
sendData();
|
||||||
|
sendZero();
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::sendPreamble(void)
|
||||||
|
{
|
||||||
|
if (protocol == 2) {
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
time_marker += 9;
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
time_marker += 9;
|
||||||
|
}
|
||||||
|
if (protocol == 3) {
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
time_marker += 4;
|
||||||
|
sendLSB(0xF);
|
||||||
|
sendLSB(0xF);
|
||||||
|
time_marker += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum129(void)
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[9] &= 0xF0;
|
||||||
|
SendBuffer[10] = 0x00;
|
||||||
|
SendBuffer[11] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0x00;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 2)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendBuffer[9] += summ & 0x0F;
|
||||||
|
SendBuffer[10] += summ & 0xF0;
|
||||||
|
SendBuffer[10] += crc & 0x0F;
|
||||||
|
SendBuffer[11] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum968(void)
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[9] &= 0xF0;
|
||||||
|
SendBuffer[10] = 0x00;
|
||||||
|
SendBuffer[11] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0xA1;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 2)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendBuffer[9] += summ & 0x0F;
|
||||||
|
SendBuffer[10] += summ & 0xF0;
|
||||||
|
SendBuffer[10] += crc & 0x0F;
|
||||||
|
SendBuffer[11] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum132(void)
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[7] &= 0xF0;
|
||||||
|
SendBuffer[8] = 0x00;
|
||||||
|
SendBuffer[9] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0x3C;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 2)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendBuffer[7] += summ & 0x0F;
|
||||||
|
SendBuffer[8] += summ & 0xF0;
|
||||||
|
SendBuffer[8] += crc & 0x0F;
|
||||||
|
SendBuffer[9] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum132S(void)
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0xD6;
|
||||||
|
SendBuffer[6] = SendBuffer[7] = 0x00;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 2)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
|
||||||
|
SendBuffer[6] += (summ & 0x0F) << 4;
|
||||||
|
SendBuffer[6] += (summ & 0xF0) >> 4;
|
||||||
|
SendBuffer[7] += (crc & 0x0F) << 4;
|
||||||
|
SendBuffer[7] += (crc & 0xF0) >> 4;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum318()
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[7] = SendBuffer[7] & 0xF0;
|
||||||
|
SendBuffer[8] = 0x00;
|
||||||
|
SendBuffer[9] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0x00;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 3)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
if (i != 2)
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendBuffer[7] += summ & 0x0F;
|
||||||
|
SendBuffer[8] += summ & 0xF0;
|
||||||
|
SendBuffer[8] += crc & 0x0F;
|
||||||
|
SendBuffer[9] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::calculateAndSetChecksum810()
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[7] = SendBuffer[7] & 0xF0;
|
||||||
|
SendBuffer[8] = 0x00;
|
||||||
|
SendBuffer[9] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0x00;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
{
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SendBuffer[7] += summ & 0x0F;
|
||||||
|
SendBuffer[8] += summ & 0xF0;
|
||||||
|
SendBuffer[8] += crc & 0x0F;
|
||||||
|
SendBuffer[9] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::SendPacket()
|
||||||
|
{
|
||||||
|
if (sens_type == BTHR968)
|
||||||
|
calculateAndSetChecksum968();
|
||||||
|
if (sens_type == BTHGN129)
|
||||||
|
calculateAndSetChecksum129();
|
||||||
|
if (sens_type == THGN132)
|
||||||
|
calculateAndSetChecksum132();
|
||||||
|
if (sens_type == THN132)
|
||||||
|
calculateAndSetChecksum132S();
|
||||||
|
if (sens_type == RTGN318)
|
||||||
|
calculateAndSetChecksum318();
|
||||||
|
if (sens_type == THGR810)
|
||||||
|
calculateAndSetChecksum810();
|
||||||
|
if (sens_type == THP)
|
||||||
|
calculateAndSetChecksumTHP();
|
||||||
|
|
||||||
|
sendOregon();
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
if (protocol == 2) {
|
||||||
|
delayMicroseconds(TWOTR_TIME * 15);
|
||||||
|
sendOregon();
|
||||||
|
digitalWrite(TX_PIN, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Функции кодирования данных//////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setType(word type)
|
||||||
|
{
|
||||||
|
sens_type = type;
|
||||||
|
if (type == THP)
|
||||||
|
{
|
||||||
|
SendBuffer[0] = 0x55;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SendBuffer[0] = (type & 0xFF00) >> 8;
|
||||||
|
SendBuffer[1] = type & 0x00FF;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setChannel(byte channel)
|
||||||
|
{
|
||||||
|
byte channel_code;
|
||||||
|
|
||||||
|
if (sens_type == BTHR968)
|
||||||
|
{
|
||||||
|
channel_code = 0x00;
|
||||||
|
setId(0xF0);
|
||||||
|
send_time = 40000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sens_type == THGN132)
|
||||||
|
{
|
||||||
|
if (channel <= 1)
|
||||||
|
{
|
||||||
|
channel_code = 0x10;
|
||||||
|
setId(0xE3);
|
||||||
|
send_time = 39000;
|
||||||
|
}
|
||||||
|
if (channel == 2)
|
||||||
|
{
|
||||||
|
channel_code = 0x20;
|
||||||
|
setId(0xE3);
|
||||||
|
send_time = 41000;
|
||||||
|
}
|
||||||
|
if (channel == 3)
|
||||||
|
{
|
||||||
|
channel_code = 0x40;
|
||||||
|
setId(0xBB);
|
||||||
|
send_time = 43000;
|
||||||
|
}
|
||||||
|
protocol = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sens_type == THN132)
|
||||||
|
{
|
||||||
|
if (channel <= 1)
|
||||||
|
{
|
||||||
|
channel_code = 0x10;
|
||||||
|
setId(0xE3);
|
||||||
|
send_time = 39000;
|
||||||
|
}
|
||||||
|
if (channel == 2)
|
||||||
|
{
|
||||||
|
channel_code = 0x20;
|
||||||
|
setId(0xE3);
|
||||||
|
send_time = 41000;
|
||||||
|
}
|
||||||
|
if (channel == 3)
|
||||||
|
{
|
||||||
|
channel_code = 0x40;
|
||||||
|
setId(0xBB);
|
||||||
|
send_time = 43000;
|
||||||
|
}
|
||||||
|
protocol = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (sens_type == RTGN318 || sens_type == BTHGN129)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (channel <= 1)
|
||||||
|
{
|
||||||
|
channel_code = 0x10;
|
||||||
|
setId(0xF1);
|
||||||
|
send_time = 53000;
|
||||||
|
}
|
||||||
|
if (channel == 2)
|
||||||
|
{
|
||||||
|
channel_code = 0x20;
|
||||||
|
setId(0x92);
|
||||||
|
send_time = 59000;
|
||||||
|
}
|
||||||
|
if (channel == 3)
|
||||||
|
{
|
||||||
|
channel_code = 0x30;
|
||||||
|
setId(0xAA);
|
||||||
|
send_time = 61000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel == 4)
|
||||||
|
{
|
||||||
|
channel_code = 0x40;
|
||||||
|
setId(0x8A);
|
||||||
|
send_time = 67000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel >= 5)
|
||||||
|
{
|
||||||
|
channel_code = 0x50;
|
||||||
|
setId(0xB1);
|
||||||
|
send_time = 71000;
|
||||||
|
}
|
||||||
|
protocol = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sens_type == THGR810)
|
||||||
|
{
|
||||||
|
if (channel <= 1)
|
||||||
|
{
|
||||||
|
channel_code = 0x10;
|
||||||
|
setId(0xCB);
|
||||||
|
send_time = 53000;
|
||||||
|
}
|
||||||
|
if (channel == 2)
|
||||||
|
{
|
||||||
|
channel_code = 0x20;
|
||||||
|
setId(0x69);
|
||||||
|
send_time = 59000;
|
||||||
|
}
|
||||||
|
if (channel == 3)
|
||||||
|
{
|
||||||
|
channel_code = 0x30;
|
||||||
|
setId(0xAA);
|
||||||
|
send_time = 61000;
|
||||||
|
}
|
||||||
|
if (channel == 4)
|
||||||
|
{
|
||||||
|
channel_code = 0x40;
|
||||||
|
setId(0x8A);
|
||||||
|
send_time = 67000;
|
||||||
|
}
|
||||||
|
if (channel == 5)
|
||||||
|
{
|
||||||
|
channel_code = 0x50;
|
||||||
|
setId(0xB1);
|
||||||
|
send_time = 71000;
|
||||||
|
}
|
||||||
|
if (channel == 6)
|
||||||
|
{
|
||||||
|
channel_code = 0x60;
|
||||||
|
send_time = 79000;
|
||||||
|
}
|
||||||
|
if (channel == 7)
|
||||||
|
{
|
||||||
|
channel_code = 0x70;
|
||||||
|
send_time = 83000;
|
||||||
|
}
|
||||||
|
if (channel == 8)
|
||||||
|
{
|
||||||
|
channel_code = 0x80;
|
||||||
|
send_time = 87000;
|
||||||
|
}
|
||||||
|
if (channel == 9)
|
||||||
|
{
|
||||||
|
channel_code = 0x90;
|
||||||
|
send_time = 91000;
|
||||||
|
}
|
||||||
|
if (channel >= 10)
|
||||||
|
{
|
||||||
|
channel_code = 0xA0;
|
||||||
|
send_time = 93000;
|
||||||
|
}
|
||||||
|
protocol = 3;
|
||||||
|
}
|
||||||
|
SendBuffer[2] &= 0x0F;
|
||||||
|
SendBuffer[2] += channel_code & 0xF0;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setId(byte ID)
|
||||||
|
{
|
||||||
|
SendBuffer[2] &= 0xF0;
|
||||||
|
SendBuffer[2] += (ID & 0xF0) >> 4;
|
||||||
|
SendBuffer[3] &= 0x0F;
|
||||||
|
SendBuffer[3] += (ID & 0x0F) << 4;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setBatteryFlag(bool level)
|
||||||
|
{
|
||||||
|
SendBuffer[3] &= 0xFB;
|
||||||
|
if (level) SendBuffer[3] |= 0x04;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setStartCount(byte startcount)
|
||||||
|
{
|
||||||
|
SendBuffer[3] &= 0xF4;
|
||||||
|
if (startcount == 8) SendBuffer[3] |= 0x08;
|
||||||
|
if (startcount == 2) SendBuffer[3] |= 0x02;
|
||||||
|
if (startcount == 1) SendBuffer[3] |= 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setPressure(float mm_hg_pressure)
|
||||||
|
{
|
||||||
|
//Ограничения датчика по даташиту
|
||||||
|
word pressure = (word)(mm_hg_pressure / 0.75);
|
||||||
|
if (mm_hg_pressure < 450) pressure = 600;
|
||||||
|
if (mm_hg_pressure > 790) pressure = 1054;
|
||||||
|
|
||||||
|
if (sens_type == BTHR968)
|
||||||
|
{
|
||||||
|
pressure -= 600;
|
||||||
|
SendBuffer[7] &= 0xF0;
|
||||||
|
SendBuffer[7] += pressure & 0x0F;
|
||||||
|
SendBuffer[8] = (pressure & 0x0F0) + ((pressure & 0xF00) >> 8);
|
||||||
|
//прогноз - переменно
|
||||||
|
SendBuffer[9] &= 0x0F;
|
||||||
|
SendBuffer[9] += 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sens_type == BTHGN129)
|
||||||
|
{
|
||||||
|
pressure -= 545;
|
||||||
|
SendBuffer[7] &= 0xF0;
|
||||||
|
SendBuffer[7] += pressure & 0x0F;
|
||||||
|
SendBuffer[8] = (pressure & 0x0F0) + ((pressure & 0xF00) >> 8);
|
||||||
|
SendBuffer[9] &= 0x0F;
|
||||||
|
SendBuffer[9] += 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setTemperature(float temp)
|
||||||
|
{
|
||||||
|
if (temp < 0)
|
||||||
|
{
|
||||||
|
SendBuffer[5] = 0x08;
|
||||||
|
temp *= -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendBuffer[5] = 0x00;
|
||||||
|
}
|
||||||
|
byte tempInt = (byte) temp;
|
||||||
|
byte td = (tempInt / 10);
|
||||||
|
byte tf = tempInt - td * 10;
|
||||||
|
byte tempFloat = (temp - (float)tempInt) * 10;
|
||||||
|
|
||||||
|
SendBuffer[5] += (td << 4);
|
||||||
|
SendBuffer[4] = tf;
|
||||||
|
SendBuffer[4] |= (tempFloat << 4);
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setHumidity(byte hum)
|
||||||
|
{
|
||||||
|
if (sens_type != THN132)
|
||||||
|
{
|
||||||
|
SendBuffer[6] = (hum / 16);
|
||||||
|
SendBuffer[6] += (hum - (SendBuffer[6] * 16)) << 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Oregon_TM::setComfort(float temp, byte hum)
|
||||||
|
{
|
||||||
|
if (sens_type != THN132)
|
||||||
|
{
|
||||||
|
if (hum > 70)
|
||||||
|
{
|
||||||
|
SendBuffer[7] = 0xC0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (hum < 40)
|
||||||
|
{
|
||||||
|
SendBuffer[7] = 0x80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (temp > 20 && temp < 25)
|
||||||
|
{
|
||||||
|
SendBuffer[7] = 0x40;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else SendBuffer[7] = 0x00;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool Oregon_TM::transmit()
|
||||||
|
{
|
||||||
|
if (millis() >= time_marker_send && send_time)
|
||||||
|
{
|
||||||
|
SendPacket();
|
||||||
|
time_marker_send = millis() + send_time;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//Поддержка датчика THP
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
void Oregon_TM::setChannelTHP(byte channel)
|
||||||
|
{
|
||||||
|
SendBuffer[1] &= 0x0F;
|
||||||
|
SendBuffer[1] += channel << 4;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setBatteryTHP( word bat_voltage)
|
||||||
|
{
|
||||||
|
SendBuffer[6] = (bat_voltage & 0x0FF0) >> 4;
|
||||||
|
SendBuffer[7] &= 0x0F;
|
||||||
|
SendBuffer[7] += (bat_voltage & 0x000F) << 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setTemperatureTHP(float bme_temperature)
|
||||||
|
{
|
||||||
|
word temp_code;
|
||||||
|
if (bme_temperature < -100 || bme_temperature > 100) temp_code = 0x0FFF;
|
||||||
|
else temp_code = (word)((bme_temperature + 100) * 10);
|
||||||
|
SendBuffer[2] = temp_code & 0x00FF;
|
||||||
|
SendBuffer[1] &= 0xF0;
|
||||||
|
SendBuffer[1] += (temp_code & 0x0F00) >> 8;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setHumidityTHP(float bme_humidity)
|
||||||
|
{
|
||||||
|
word hum_code;
|
||||||
|
if (bme_humidity > 100) hum_code = 0x0FFF;
|
||||||
|
else hum_code = (word)(bme_humidity * 10);
|
||||||
|
SendBuffer[3] = (hum_code & 0x0FF0) >> 4;
|
||||||
|
SendBuffer[4] &= 0x0F;
|
||||||
|
SendBuffer[4] += (hum_code & 0x000F) << 4;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setPressureTHP(float bme_pressure)
|
||||||
|
{
|
||||||
|
word pres_code;
|
||||||
|
if (bme_pressure < 500) pres_code = 0x0000;
|
||||||
|
else pres_code = (word)((bme_pressure - 500) * 10);
|
||||||
|
SendBuffer[5] = pres_code & 0x00FF;
|
||||||
|
SendBuffer[4] &= 0xF0;
|
||||||
|
SendBuffer[4] += (pres_code & 0x0F00) >> 8;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::setErrorTHP()
|
||||||
|
{
|
||||||
|
SendBuffer[1] |= 0x0F;
|
||||||
|
SendBuffer[2] = 0xFF;
|
||||||
|
SendBuffer[3] = 0xFF;
|
||||||
|
SendBuffer[4] = 0xFF;
|
||||||
|
SendBuffer[5] = 0xFF;
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void Oregon_TM::calculateAndSetChecksumTHP()
|
||||||
|
{
|
||||||
|
byte CCIT_POLY = 0x07;
|
||||||
|
SendBuffer[7] = SendBuffer[7] & 0xF0;
|
||||||
|
SendBuffer[8] = 0x00;
|
||||||
|
SendBuffer[9] = 0x00;
|
||||||
|
byte summ = 0x00;
|
||||||
|
byte crc = 0x00;
|
||||||
|
byte cur_nible;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
cur_nible = (SendBuffer[i] & 0xF0) >> 4;
|
||||||
|
summ += cur_nible;
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
|
||||||
|
cur_nible = SendBuffer[i] & 0x0F;
|
||||||
|
summ += cur_nible;
|
||||||
|
crc ^= cur_nible;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ CCIT_POLY;
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
SendBuffer[7] += summ & 0x0F;
|
||||||
|
SendBuffer[8] += summ & 0xF0;
|
||||||
|
SendBuffer[8] += crc & 0x0F;
|
||||||
|
SendBuffer[9] += crc & 0xF0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#ifndef Oregon_TM_h
|
||||||
|
#define Oregon_TM_h
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// This file is part of the Arduino OREGON_NR library.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Sergey Zawislak
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Этот файл - часть библиотеки OREGON_NR
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 Сергей Зависляк
|
||||||
|
//
|
||||||
|
// Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации
|
||||||
|
// (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений,
|
||||||
|
// включая неограниченное право на использование, копирование, изменение, слияние, публикацию, распространение, сублицензирование
|
||||||
|
// и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:
|
||||||
|
//
|
||||||
|
// Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения.
|
||||||
|
//
|
||||||
|
// ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ
|
||||||
|
// ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ
|
||||||
|
// НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ,
|
||||||
|
// ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define TR_TIME 488
|
||||||
|
#define TWOTR_TIME 976
|
||||||
|
#define PULSE_SHORTEN_2 93
|
||||||
|
#define PULSE_SHORTEN_3 138
|
||||||
|
|
||||||
|
#define THGN132 0x1D20
|
||||||
|
#define THN132 0xEC40
|
||||||
|
#define THGR810 0xF824
|
||||||
|
#define RTGN318 0xDCC3
|
||||||
|
#define THP 0x5500
|
||||||
|
#define BTHGN129 0x5D53
|
||||||
|
#define BTHR968 0x5D60
|
||||||
|
|
||||||
|
|
||||||
|
#define OREGON_SEND_BUFFER_SIZE 12
|
||||||
|
|
||||||
|
//static byte TX_PIN = 4;
|
||||||
|
static byte TX_PIN;
|
||||||
|
|
||||||
|
|
||||||
|
class Oregon_TM
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
int max_buffer_size = OREGON_SEND_BUFFER_SIZE;
|
||||||
|
int buffer_size = 24;
|
||||||
|
byte* SendBuffer;
|
||||||
|
byte protocol = 2;
|
||||||
|
word sens_type = 0x0000;
|
||||||
|
int timing_corrector2 = 4;
|
||||||
|
int timing_corrector3 = 2;
|
||||||
|
|
||||||
|
Oregon_TM(byte, int);
|
||||||
|
Oregon_TM(byte);
|
||||||
|
Oregon_TM();
|
||||||
|
void setType(word);
|
||||||
|
void setChannel( byte);
|
||||||
|
void setId(byte);
|
||||||
|
void setBatteryFlag(bool);
|
||||||
|
void setStartCount(byte);
|
||||||
|
void setTemperature(float);
|
||||||
|
void setHumidity(byte);
|
||||||
|
void setComfort(float, byte);
|
||||||
|
void setPressure(float);
|
||||||
|
bool transmit();
|
||||||
|
void SendPacket();
|
||||||
|
|
||||||
|
void setErrorTHP();
|
||||||
|
void setPressureTHP(float);
|
||||||
|
void setTemperatureTHP(float);
|
||||||
|
void setBatteryTHP(word);
|
||||||
|
void setChannelTHP(byte);
|
||||||
|
void setHumidityTHP(float);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void sendZero(void);
|
||||||
|
void sendOne(void);
|
||||||
|
void sendMSB(const byte);
|
||||||
|
void sendLSB(const byte);
|
||||||
|
void sendData();
|
||||||
|
void sendOregon();
|
||||||
|
void sendPreamble();
|
||||||
|
void calculateAndSetChecksum132();
|
||||||
|
void calculateAndSetChecksum318();
|
||||||
|
void calculateAndSetChecksum810();
|
||||||
|
void calculateAndSetChecksum968();
|
||||||
|
void calculateAndSetChecksum129();
|
||||||
|
void calculateAndSetChecksum132S();
|
||||||
|
|
||||||
|
|
||||||
|
void calculateAndSetChecksumTHP();
|
||||||
|
|
||||||
|
unsigned long time_marker = 0;
|
||||||
|
unsigned long time_marker_send = 0;
|
||||||
|
unsigned long send_time = 0;
|
||||||
|
bool prevbit = 1;
|
||||||
|
bool prevstate = 1;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <Oregon_TM.h>
|
||||||
|
|
||||||
|
//Имитатор датчиков температуры и влажности Oregon Scientific
|
||||||
|
|
||||||
|
//В данном примере иммитируются пакеты следующих типов датчиков:
|
||||||
|
//THGN132N (тип 1D20h, протокол v2, 3 канала)
|
||||||
|
//RTGN318 (тип ХСС3h, протокол v2, 5 каналов)
|
||||||
|
//THGR810 (тип F824h, протокол v3, 10 каналов)
|
||||||
|
//BTHR968 (тип 5D60h, протокол v2, 1 канал)
|
||||||
|
//BTHGN129 (тип 5D53h, протокол v2, 5 каналов)
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//Вывод передатчика один. Указывается только при создании первого объекта. В данном примере передатчик подключен к D4
|
||||||
|
|
||||||
|
Oregon_TM transmitter(4);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
//Serial.begin(9600);
|
||||||
|
|
||||||
|
//THGN132
|
||||||
|
//transmitter.setType(THGN132);
|
||||||
|
transmitter.setType(THGR810);
|
||||||
|
//transmitter.setType(RTGN318);
|
||||||
|
//transmitter.setType(BTHGN129);
|
||||||
|
//transmitter.setType(BTHR968);
|
||||||
|
transmitter.setChannel(3); // Номер канала для THGN132 - 1...3
|
||||||
|
transmitter.setBatteryFlag(1); // Флаг разряженной батарейки
|
||||||
|
//transmitter.setComfort(24.2, 30); // Расчёт передаваемого индекса комфорта
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
//передача осуществляется по таймеру, который определяется типом датчика и номером канала
|
||||||
|
|
||||||
|
//Serial.println("TX");
|
||||||
|
// Displays temperatures from -10 degrees Celsius to +20,
|
||||||
|
// and humidity from 10% REL to 40% REL, with increments of 2
|
||||||
|
for (int i = -10; i<=20; i+=2) {
|
||||||
|
// Temperatures are passed at 10 times the real value,
|
||||||
|
// to avoid using floating point math.
|
||||||
|
transmitter.setTemperature((float) i); // -49.9C...+69.9C
|
||||||
|
transmitter.setHumidity(i+20); // 2...98%
|
||||||
|
transmitter.SendPacket();
|
||||||
|
|
||||||
|
// Wait two seconds before sending next.
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/*void PrintSentData(byte* buf, int buf_size)
|
||||||
|
{
|
||||||
|
Serial.print(millis() / 1000);
|
||||||
|
Serial.print("s \t\t");
|
||||||
|
for (byte i = 0; i < buf_size; i++)
|
||||||
|
{
|
||||||
|
byte trmbuf = *buf;
|
||||||
|
Serial.print(trmbuf >> 4, HEX);
|
||||||
|
i++;
|
||||||
|
if (i >= buf_size) break;
|
||||||
|
Serial.print(trmbuf & 0x0F, HEX);
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
delay(1000);
|
||||||
|
}*/
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* RemoteSensor library v1.0.2 (20130601) for Arduino 1.0
|
||||||
|
*
|
||||||
|
* This library encodes, encrypts en transmits data to
|
||||||
|
* remote weather stations made by Hideki Electronics..
|
||||||
|
*
|
||||||
|
* Copyright 2011-2013 by Randy Simons http://randysimons.nl/
|
||||||
|
*
|
||||||
|
* Parts of this code based on Oopsje's CrestaProtocol.pdf, for which
|
||||||
|
* I thank him very much!
|
||||||
|
*
|
||||||
|
* License: GPLv3. See license.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SensorTransmitter.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************
|
||||||
|
* Sensor base class
|
||||||
|
******************/
|
||||||
|
|
||||||
|
SensorTransmitter::SensorTransmitter(byte transmitterPin, byte randomId) {
|
||||||
|
_transmitterPin = transmitterPin;
|
||||||
|
_randomId = randomId;
|
||||||
|
|
||||||
|
pinMode(_transmitterPin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encrypt data byte to send to station */
|
||||||
|
byte SensorTransmitter::encryptByte(byte b) {
|
||||||
|
byte a;
|
||||||
|
for(a=0; b; b<<=1) {
|
||||||
|
a^=b;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The second checksum. Input is OldChecksum^NewByte */
|
||||||
|
byte SensorTransmitter::secondCheck(byte b) {
|
||||||
|
byte c;
|
||||||
|
if (b&0x80) {
|
||||||
|
b^=0x95;
|
||||||
|
}
|
||||||
|
c = b^(b>>1);
|
||||||
|
if (b&1) {
|
||||||
|
c^=0x5f;
|
||||||
|
}
|
||||||
|
if (c&1) {
|
||||||
|
b^=0x5f;
|
||||||
|
}
|
||||||
|
return b^(c>>1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example to encrypt a package for sending,
|
||||||
|
Input: Buffer holds the unencrypted data.
|
||||||
|
Returns the number of bytes to send,
|
||||||
|
Buffer now holds data ready for sending.
|
||||||
|
*/
|
||||||
|
byte SensorTransmitter::encryptAndAddCheck(byte *buffer) {
|
||||||
|
byte cs1,cs2,count,i;
|
||||||
|
|
||||||
|
count=(buffer[2]>>1) & 0x1f;
|
||||||
|
cs1=0;
|
||||||
|
cs2=0;
|
||||||
|
for(i=1; i<count+1; i++) {
|
||||||
|
buffer[i]=encryptByte(buffer[i]);
|
||||||
|
cs1^=buffer[i];
|
||||||
|
cs2 =secondCheck(buffer[i]^cs2);
|
||||||
|
}
|
||||||
|
buffer[count+1]=cs1;
|
||||||
|
buffer[count+2]=secondCheck(cs1^cs2);
|
||||||
|
return count+3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send one byte and keep the transmitter ready to send the next */
|
||||||
|
void SensorTransmitter::sendManchesterByte(byte transmitterPin, byte b) {
|
||||||
|
byte i;
|
||||||
|
|
||||||
|
// Send start-bit 0.
|
||||||
|
digitalWrite(transmitterPin, LOW);
|
||||||
|
delayMicroseconds(500);
|
||||||
|
digitalWrite(transmitterPin, HIGH);
|
||||||
|
delayMicroseconds(500);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
if (b&1) {
|
||||||
|
digitalWrite(transmitterPin, HIGH);
|
||||||
|
} else {
|
||||||
|
digitalWrite(transmitterPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
delayMicroseconds(500); /* 500uS delay */
|
||||||
|
|
||||||
|
b=~b;
|
||||||
|
if (i&1) {
|
||||||
|
b>>=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send bytes (prepared by “encryptAndAddCheck”) and pause at the end. */
|
||||||
|
void SensorTransmitter::sendManchesterPackage(byte transmitterPin, byte *data, byte cnt) {
|
||||||
|
byte i;
|
||||||
|
|
||||||
|
for (i=0; i<cnt; i++) {
|
||||||
|
sendManchesterByte(transmitterPin, data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(transmitterPin, LOW); /* Drop the transmitter line */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts, adds checksums and transmits the data. The value of byte 3 in the data is ignored.
|
||||||
|
*/
|
||||||
|
void SensorTransmitter::sendPackage(byte transmitterPin, byte *data) {
|
||||||
|
byte buffer[14], temp, count;
|
||||||
|
for (temp=0x40; temp>=0x40; temp+=0x40) { /* Sends 3 packages */
|
||||||
|
memcpy(buffer, data, ((data[2] >> 1) & 0x1f) + 1);
|
||||||
|
|
||||||
|
buffer[3] = (buffer[3] & 0x1f) + temp;
|
||||||
|
|
||||||
|
count = encryptAndAddCheck(buffer); /* Encrypt, add checksum bytes */
|
||||||
|
sendManchesterPackage(transmitterPin, buffer,count); /* Send the package */
|
||||||
|
|
||||||
|
delay(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* Thermo / Hygro sensor transmitter
|
||||||
|
***********************************/
|
||||||
|
|
||||||
|
ThermoHygroTransmitter::ThermoHygroTransmitter(byte transmitterPin, byte randomId, byte channel) : SensorTransmitter(transmitterPin, randomId) {
|
||||||
|
_channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThermoHygroTransmitter::sendTempHumi(int temperature, byte humidity) {
|
||||||
|
byte buffer[10];
|
||||||
|
|
||||||
|
// Note: temperature is 10x the actual temperature! So, 23.5 degrees is passed as 235.
|
||||||
|
|
||||||
|
buffer[0] = 0x75; /* Header byte */
|
||||||
|
buffer[1] = (_channel << 5) | _randomId ; /* Thermo-hygro at channel 1 (see table1)*/
|
||||||
|
buffer[2] = 0xce; /* Package size byte for th-sensor */
|
||||||
|
buffer[3] = 0x1e; /* Themo/Hygro */
|
||||||
|
|
||||||
|
if ( temperature < 0 ) {
|
||||||
|
buffer[5] = 0x4 << 4; // High nibble is 0x4 for sub zero temperatures...
|
||||||
|
temperature = -temperature; // Make temperature positive
|
||||||
|
} else {
|
||||||
|
buffer[5] = 0xc << 4; // ...0xc for positive
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: temperature is now always positive!
|
||||||
|
buffer[4] = (((temperature % 100) / 10 ) << 4) | // the "3" from 23.5
|
||||||
|
(temperature % 10); // the "5" from 23.5
|
||||||
|
buffer[5] |= (temperature / 100); // the "2" from 23.5
|
||||||
|
|
||||||
|
buffer[6] = ((humidity / 10) << 4) | (humidity % 10); // BCD encoded
|
||||||
|
|
||||||
|
buffer[7]=0xff; /* Comfort flag */
|
||||||
|
|
||||||
|
sendPackage(_transmitterPin, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThermoHygroTransmitter::sendRainlevel(unsigned int level){ // in 0.7mm
|
||||||
|
byte buffer[10];
|
||||||
|
|
||||||
|
// Note: temperature is 10x the actual temperature! So, 23.5 degrees is passed as 235.
|
||||||
|
|
||||||
|
buffer[0] = 0x75; /* Header byte */
|
||||||
|
buffer[1] = (_channel << 5) | _randomId ; /* Thermo-hygro at channel 1 (see table1)*/
|
||||||
|
buffer[2] = 0xcc; /* Package size byte for rain-sensor */
|
||||||
|
buffer[3] = 0x0e; /* Rain level */
|
||||||
|
|
||||||
|
// Note: temperature is now always positive!
|
||||||
|
buffer[4] = level & 0xff; // Low byte
|
||||||
|
buffer[5] = (level >>8) & 0xff; // High byte
|
||||||
|
|
||||||
|
sendPackage(_transmitterPin, buffer);
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* RemoteSensor library v1.0.2 (20130601) for Arduino 1.0
|
||||||
|
*
|
||||||
|
* This library encodes, encrypts en transmits data to
|
||||||
|
* remote weather stations made by Hideki Electronics..
|
||||||
|
*
|
||||||
|
* Copyright 2011-2013 by Randy Simons http://randysimons.nl/
|
||||||
|
*
|
||||||
|
* Parts of this code based on Oopsje's CrestaProtocol.pdf, for which
|
||||||
|
* I thank him very much!
|
||||||
|
*
|
||||||
|
* License: GPLv3. See license.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SensorTransmitter_h
|
||||||
|
#define SensorTransmitter_h
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SensorTransmitter provides a generic class to simulate Cresta weather sensors, for use
|
||||||
|
* with Cresta weather stations.
|
||||||
|
* E.g. http://www.cresta.nl/index.php?Itemid=2&option=com_zoo&view=item&category_id=32&item_id=281&lang=en
|
||||||
|
*
|
||||||
|
* Cresta is just a brand name. The original OEM seems to be Hideki Electronics. There are
|
||||||
|
* other brands which use the same hardware and / or protocol. As far as I know these include
|
||||||
|
* Mebus, Irox, Honeywell, Cresta and RST.
|
||||||
|
*
|
||||||
|
* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g.
|
||||||
|
* http://www.sparkfun.com/products/10534
|
||||||
|
* http://www.conrad.nl/goto/?product=130428
|
||||||
|
*/
|
||||||
|
class SensorTransmitter {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Initializes the transmitter. About the random id: "A sensor selects a random value
|
||||||
|
* in the range of column 1 when it is reset. It keeps the same ID until it is reset again."
|
||||||
|
* You can leave it at 0 for most purposes
|
||||||
|
* The transmitter pin is set in OUTPUT mode; you don't have to do this yourself.
|
||||||
|
*
|
||||||
|
* @param transmitterPin Arduino-pin connected to the 433MHz transmitter
|
||||||
|
* @param randomId A "random" value in the range [0..31]
|
||||||
|
*/
|
||||||
|
SensorTransmitter(byte transmitterPin, byte randomId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a raw sensor package. Before transmitting, the data is encrypted and checksums are
|
||||||
|
* added. The buffer of the data doesn't need to have room for the checksums, as the data is
|
||||||
|
* copied internally to a new buffer which is always large enough.
|
||||||
|
* However, the data must be valid!
|
||||||
|
*
|
||||||
|
* The data is transmitted 3 times.
|
||||||
|
*
|
||||||
|
* Note that this is a static method.
|
||||||
|
*
|
||||||
|
* @param transmitterPin Arduino-pin connected to the 433MHz transmitter
|
||||||
|
* @param data Pointer to data to transmit
|
||||||
|
*/
|
||||||
|
static void sendPackage(byte transmitterPin, byte *data);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
byte _transmitterPin;
|
||||||
|
byte _randomId;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Sends data as manchester encoded stream
|
||||||
|
*/
|
||||||
|
static void sendManchesterPackage(byte transmitterPin, byte *data, byte cnt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a single byte as manchester encoded stream
|
||||||
|
*/
|
||||||
|
static void sendManchesterByte(byte transmitterPin, byte b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encryption and checksum
|
||||||
|
*/
|
||||||
|
static byte encryptAndAddCheck(byte *buffer);
|
||||||
|
static byte secondCheck(byte b);
|
||||||
|
static byte encryptByte(byte b);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ThermoHygroTransmitter : public SensorTransmitter {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Mimics a Thermo / Hygro sensor. The channel of this device can be 1..5, but note
|
||||||
|
* that only the more expensive receivers can use channels 4 and 5. However, for use
|
||||||
|
* in conjunction with SensorReceiver this is of no concern.
|
||||||
|
*
|
||||||
|
* @param transmitterPin Arduino-pin connected to the 433MHz transmitter
|
||||||
|
* @param randomId A "random" value in the range [0..31]
|
||||||
|
* @channel The channel of this sensor, range [1..5]
|
||||||
|
* @see SensorTransmitter::SensorTransmitter (constructor)
|
||||||
|
*/
|
||||||
|
ThermoHygroTransmitter(byte transmitterPin, byte randomId, byte channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends temperature and humidity.
|
||||||
|
*
|
||||||
|
* @param temperature 10x the actual temperature. You want to send 23,5 degrees, then temperature should be 235.
|
||||||
|
* @param humidty Humidity in percentage-points REL. Thus, for 34% REH humidity should be 34.
|
||||||
|
*/
|
||||||
|
void sendTempHumi(int temperature, byte humidity);
|
||||||
|
void sendRainlevel(unsigned int level); // in 0.7mm
|
||||||
|
|
||||||
|
private:
|
||||||
|
byte _channel; // Note: internally, the channels for the thermo/hygro-sensor are mapped as follow:
|
||||||
|
// 1=>1, 2=>2, 3=>3, 4=>5, 5=>6.
|
||||||
|
// This because interally the rain sensor, UV sensor and anemometer are on channel 4.
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* This sketch sends (bogus) thermo / hygro data to a remote weather sensors made by Cresta.
|
||||||
|
*
|
||||||
|
* Setup:
|
||||||
|
* - connect transmitter input of a 433MHz transmitter to digital pin 11
|
||||||
|
* - On the weather station, activate the "scan" function for channel 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SensorTransmitter.h>
|
||||||
|
|
||||||
|
// Initializes a ThermoHygroTransmitter on pin 11, with "random" ID 0, on channel 1.
|
||||||
|
ThermoHygroTransmitter transmitter(4, 0, 1);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Displays temperatures from -10 degrees Celsius to +20,
|
||||||
|
// and humidity from 10% REL to 40% REL, with increments of 2
|
||||||
|
for (int i = -10; i<=20; i+=2) {
|
||||||
|
// Temperatures are passed at 10 times the real value,
|
||||||
|
// to avoid using floating point math.
|
||||||
|
transmitter.sendTempHumi(i * 10, i + 20);
|
||||||
|
|
||||||
|
// Wait two seconds before sending next.
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Mac stuff
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"type": "library", "name": "rc-switch", "version": "2.6.4", "spec": {"owner": "sui77", "id": 246, "name": "rc-switch", "requirements": null, "uri": null}}
|
|
@ -0,0 +1,70 @@
|
||||||
|
language: c
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
|
||||||
|
# Cache PlatformIO packages using Travis CI container-based infrastructure
|
||||||
|
cache:
|
||||||
|
pip: true
|
||||||
|
directories:
|
||||||
|
- "~/.platformio"
|
||||||
|
|
||||||
|
env:
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/Webserver
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/Webserver.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Simple
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Simple.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/TypeC_Intertechno
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeC_Intertechno.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/TypeD_REV
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeD_REV.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/TypeA_WithDIPSwitches_Lightweight
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeA_WithDIPSwitches_Lightweight.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/TypeB_WithRotaryOrSlidingSwitches
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/TypeB_WithRotaryOrSlidingSwitches.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01 --board=attiny25 --board=attiny24"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/SendDemo
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/SendDemo.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
|
||||||
|
- >
|
||||||
|
PLATFORMIO_CI_SRC=$PWD/examples/ReceiveDemo_Advanced
|
||||||
|
ARDUINOIDE_CI_SRC=$PLATFORMIO_CI_SRC/ReceiveDemo_Advanced.ino
|
||||||
|
BOARDS="--board=diecimilaatmega328 --board=uno --board=esp01"
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# Arduino IDE
|
||||||
|
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
|
||||||
|
- sleep 3
|
||||||
|
- export DISPLAY=:1.0
|
||||||
|
- wget http://downloads.arduino.cc/arduino-1.8.10-linux64.tar.xz
|
||||||
|
- tar xf arduino-1.8.10-linux64.tar.xz
|
||||||
|
- sudo mv arduino-1.8.10 /usr/local/share/arduino
|
||||||
|
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
|
||||||
|
|
||||||
|
install:
|
||||||
|
# Arduino IDE
|
||||||
|
- ln -s $PWD /usr/local/share/arduino/libraries/rc-switch
|
||||||
|
# PlatformIO
|
||||||
|
# - pip install -U platformio
|
||||||
|
# - platformio update
|
||||||
|
|
||||||
|
script:
|
||||||
|
# Arduino IDE
|
||||||
|
- arduino --verify --board arduino:avr:uno ${ARDUINOIDE_CI_SRC}
|
||||||
|
# PlatformIO
|
||||||
|
# - platformio run --lib="." ${BOARDS}
|
|
@ -0,0 +1,712 @@
|
||||||
|
/*
|
||||||
|
RCSwitch - Arduino libary for remote control outlet switches
|
||||||
|
Copyright (c) 2011 Suat Özgür. All right reserved.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
- Andre Koehler / info(at)tomate-online(dot)de
|
||||||
|
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
|
||||||
|
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
|
||||||
|
- Dominik Fischer / dom_fischer(at)web(dot)de
|
||||||
|
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
|
||||||
|
- Andreas Steinel / A.<lastname>(at)gmail(dot)com
|
||||||
|
- Max Horn / max(at)quendi(dot)de
|
||||||
|
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
|
||||||
|
- Johann Richard / <first name>.<last name>(at)gmail(dot)com
|
||||||
|
- Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
|
||||||
|
- Matias Cuenca-Acuna
|
||||||
|
|
||||||
|
Project home: https://github.com/sui77/rc-switch/
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "RCSwitch.h"
|
||||||
|
|
||||||
|
#ifdef RaspberryPi
|
||||||
|
// PROGMEM and _P functions are for AVR based microprocessors,
|
||||||
|
// so we must normalize these for the ARM processor:
|
||||||
|
#define PROGMEM
|
||||||
|
#define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
// interrupt handler and related code must be in RAM on ESP8266,
|
||||||
|
// according to issue #46.
|
||||||
|
#define RECEIVE_ATTR ICACHE_RAM_ATTR
|
||||||
|
#define VAR_ISR_ATTR
|
||||||
|
#elif defined(ESP32)
|
||||||
|
#define RECEIVE_ATTR IRAM_ATTR
|
||||||
|
#define VAR_ISR_ATTR DRAM_ATTR
|
||||||
|
#else
|
||||||
|
#define RECEIVE_ATTR
|
||||||
|
#define VAR_ISR_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Format for protocol definitions:
|
||||||
|
* {pulselength, Sync bit, "0" bit, "1" bit, invertedSignal}
|
||||||
|
*
|
||||||
|
* pulselength: pulse length in microseconds, e.g. 350
|
||||||
|
* Sync bit: {1, 31} means 1 high pulse and 31 low pulses
|
||||||
|
* (perceived as a 31*pulselength long pulse, total length of sync bit is
|
||||||
|
* 32*pulselength microseconds), i.e:
|
||||||
|
* _
|
||||||
|
* | |_______________________________ (don't count the vertical bars)
|
||||||
|
* "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
|
||||||
|
* and 3 low pulses, total length (1+3)*pulselength, i.e:
|
||||||
|
* _
|
||||||
|
* | |___
|
||||||
|
* "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
|
||||||
|
* ___
|
||||||
|
* | |_
|
||||||
|
*
|
||||||
|
* These are combined to form Tri-State bits when sending or receiving codes.
|
||||||
|
*/
|
||||||
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
static const VAR_ISR_ATTR RCSwitch::Protocol proto[] = {
|
||||||
|
#else
|
||||||
|
static const RCSwitch::Protocol PROGMEM proto[] = {
|
||||||
|
#endif
|
||||||
|
{ 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1
|
||||||
|
{ 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2
|
||||||
|
{ 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3
|
||||||
|
{ 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4
|
||||||
|
{ 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5
|
||||||
|
{ 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B)
|
||||||
|
{ 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false }, // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
|
||||||
|
{ 200, { 3, 130}, { 7, 16 }, { 3, 16}, false}, // protocol 8 Conrad RS-200 RX
|
||||||
|
{ 200, { 130, 7 }, { 16, 7 }, { 16, 3 }, true}, // protocol 9 Conrad RS-200 TX
|
||||||
|
{ 365, { 18, 1 }, { 3, 1 }, { 1, 3 }, true }, // protocol 10 (1ByOne Doorbell)
|
||||||
|
{ 270, { 36, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 11 (HT12E)
|
||||||
|
{ 320, { 36, 1 }, { 1, 2 }, { 2, 1 }, true } // protocol 12 (SM5212)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
numProto = sizeof(proto) / sizeof(proto[0])
|
||||||
|
};
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
volatile unsigned long RCSwitch::nReceivedValue = 0;
|
||||||
|
volatile unsigned int RCSwitch::nReceivedBitlength = 0;
|
||||||
|
volatile unsigned int RCSwitch::nReceivedDelay = 0;
|
||||||
|
volatile unsigned int RCSwitch::nReceivedProtocol = 0;
|
||||||
|
int RCSwitch::nReceiveTolerance = 60;
|
||||||
|
const unsigned int RCSwitch::nSeparationLimit = 4300;
|
||||||
|
// separationLimit: minimum microseconds between received codes, closer codes are ignored.
|
||||||
|
// according to discussion on issue #14 it might be more suitable to set the separation
|
||||||
|
// limit to the same time as the 'low' part of the sync signal for the current protocol.
|
||||||
|
unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RCSwitch::RCSwitch() {
|
||||||
|
this->nTransmitterPin = -1;
|
||||||
|
this->setRepeatTransmit(10);
|
||||||
|
this->setProtocol(1);
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
this->nReceiverInterrupt = -1;
|
||||||
|
this->setReceiveTolerance(60);
|
||||||
|
RCSwitch::nReceivedValue = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the protocol to send.
|
||||||
|
*/
|
||||||
|
void RCSwitch::setProtocol(Protocol protocol) {
|
||||||
|
this->protocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the protocol to send, from a list of predefined protocols
|
||||||
|
*/
|
||||||
|
void RCSwitch::setProtocol(int nProtocol) {
|
||||||
|
if (nProtocol < 1 || nProtocol > numProto) {
|
||||||
|
nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
|
||||||
|
}
|
||||||
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
this->protocol = proto[nProtocol-1];
|
||||||
|
#else
|
||||||
|
memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the protocol to send with pulse length in microseconds.
|
||||||
|
*/
|
||||||
|
void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
|
||||||
|
setProtocol(nProtocol);
|
||||||
|
this->setPulseLength(nPulseLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets pulse length in microseconds
|
||||||
|
*/
|
||||||
|
void RCSwitch::setPulseLength(int nPulseLength) {
|
||||||
|
this->protocol.pulseLength = nPulseLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets Repeat Transmits
|
||||||
|
*/
|
||||||
|
void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
|
||||||
|
this->nRepeatTransmit = nRepeatTransmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Receiving Tolerance
|
||||||
|
*/
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
void RCSwitch::setReceiveTolerance(int nPercent) {
|
||||||
|
RCSwitch::nReceiveTolerance = nPercent;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable transmissions
|
||||||
|
*
|
||||||
|
* @param nTransmitterPin Arduino Pin to which the sender is connected to
|
||||||
|
*/
|
||||||
|
void RCSwitch::enableTransmit(int nTransmitterPin) {
|
||||||
|
this->nTransmitterPin = nTransmitterPin;
|
||||||
|
pinMode(this->nTransmitterPin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable transmissions
|
||||||
|
*/
|
||||||
|
void RCSwitch::disableTransmit() {
|
||||||
|
this->nTransmitterPin = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch on (Type D REV)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (A,B,C,D)
|
||||||
|
* @param nDevice Number of the switch itself (1..3)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOn(char sGroup, int nDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch off (Type D REV)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (A,B,C,D)
|
||||||
|
* @param nDevice Number of the switch itself (1..3)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOff(char sGroup, int nDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch on (Type C Intertechno)
|
||||||
|
*
|
||||||
|
* @param sFamily Familycode (a..f)
|
||||||
|
* @param nGroup Number of group (1..4)
|
||||||
|
* @param nDevice Number of device (1..4)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch off (Type C Intertechno)
|
||||||
|
*
|
||||||
|
* @param sFamily Familycode (a..f)
|
||||||
|
* @param nGroup Number of group (1..4)
|
||||||
|
* @param nDevice Number of device (1..4)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch on (Type B with two rotary/sliding switches)
|
||||||
|
*
|
||||||
|
* @param nAddressCode Number of the switch group (1..4)
|
||||||
|
* @param nChannelCode Number of the switch itself (1..4)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
|
||||||
|
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch off (Type B with two rotary/sliding switches)
|
||||||
|
*
|
||||||
|
* @param nAddressCode Number of the switch group (1..4)
|
||||||
|
* @param nChannelCode Number of the switch itself (1..4)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
|
||||||
|
this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
|
||||||
|
* Switch a remote switch on (Type A with 10 pole DIP switches)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
* @param nChannelCode Number of the switch itself (1..5)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOn(const char* sGroup, int nChannel) {
|
||||||
|
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
|
||||||
|
this->switchOn(sGroup, code[nChannel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
|
||||||
|
* Switch a remote switch off (Type A with 10 pole DIP switches)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
* @param nChannelCode Number of the switch itself (1..5)
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOff(const char* sGroup, int nChannel) {
|
||||||
|
const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
|
||||||
|
this->switchOff(sGroup, code[nChannel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch on (Type A with 10 pole DIP switches)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch a remote switch off (Type A with 10 pole DIP switches)
|
||||||
|
*
|
||||||
|
* @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
* @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
|
||||||
|
*/
|
||||||
|
void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
|
||||||
|
this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a char[13], representing the code word to be send.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
|
||||||
|
static char sReturn[13];
|
||||||
|
int nReturnPos = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
sReturn[nReturnPos++] = bStatus ? '0' : 'F';
|
||||||
|
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
|
||||||
|
|
||||||
|
sReturn[nReturnPos] = '\0';
|
||||||
|
return sReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoding for type B switches with two rotary/sliding switches.
|
||||||
|
*
|
||||||
|
* The code word is a tristate word and with following bit pattern:
|
||||||
|
*
|
||||||
|
* +-----------------------------+-----------------------------+----------+------------+
|
||||||
|
* | 4 bits address | 4 bits address | 3 bits | 1 bit |
|
||||||
|
* | switch group | switch number | not used | on / off |
|
||||||
|
* | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
|
||||||
|
* +-----------------------------+-----------------------------+----------+------------+
|
||||||
|
*
|
||||||
|
* @param nAddressCode Number of the switch group (1..4)
|
||||||
|
* @param nChannelCode Number of the switch itself (1..4)
|
||||||
|
* @param bStatus Whether to switch on (true) or off (false)
|
||||||
|
*
|
||||||
|
* @return char[13], representing a tristate code word of length 12
|
||||||
|
*/
|
||||||
|
char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
|
||||||
|
static char sReturn[13];
|
||||||
|
int nReturnPos = 0;
|
||||||
|
|
||||||
|
if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= 4; i++) {
|
||||||
|
sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= 4; i++) {
|
||||||
|
sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
|
||||||
|
}
|
||||||
|
|
||||||
|
sReturn[nReturnPos++] = 'F';
|
||||||
|
sReturn[nReturnPos++] = 'F';
|
||||||
|
sReturn[nReturnPos++] = 'F';
|
||||||
|
|
||||||
|
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
|
||||||
|
|
||||||
|
sReturn[nReturnPos] = '\0';
|
||||||
|
return sReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like getCodeWord (Type C = Intertechno)
|
||||||
|
*/
|
||||||
|
char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
|
||||||
|
static char sReturn[13];
|
||||||
|
int nReturnPos = 0;
|
||||||
|
|
||||||
|
int nFamily = (int)sFamily - 'a';
|
||||||
|
if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the family into four bits
|
||||||
|
sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
|
||||||
|
|
||||||
|
// encode the device and group
|
||||||
|
sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
|
||||||
|
sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
|
||||||
|
|
||||||
|
// encode the status code
|
||||||
|
sReturn[nReturnPos++] = '0';
|
||||||
|
sReturn[nReturnPos++] = 'F';
|
||||||
|
sReturn[nReturnPos++] = 'F';
|
||||||
|
sReturn[nReturnPos++] = bStatus ? 'F' : '0';
|
||||||
|
|
||||||
|
sReturn[nReturnPos] = '\0';
|
||||||
|
return sReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoding for the REV Switch Type
|
||||||
|
*
|
||||||
|
* The code word is a tristate word and with following bit pattern:
|
||||||
|
*
|
||||||
|
* +-----------------------------+-------------------+----------+--------------+
|
||||||
|
* | 4 bits address | 3 bits address | 3 bits | 2 bits |
|
||||||
|
* | switch group | device number | not used | on / off |
|
||||||
|
* | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
|
||||||
|
* +-----------------------------+-------------------+----------+--------------+
|
||||||
|
*
|
||||||
|
* Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
|
||||||
|
*
|
||||||
|
* @param sGroup Name of the switch group (A..D, resp. a..d)
|
||||||
|
* @param nDevice Number of the switch itself (1..3)
|
||||||
|
* @param bStatus Whether to switch on (true) or off (false)
|
||||||
|
*
|
||||||
|
* @return char[13], representing a tristate code word of length 12
|
||||||
|
*/
|
||||||
|
char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
|
||||||
|
static char sReturn[13];
|
||||||
|
int nReturnPos = 0;
|
||||||
|
|
||||||
|
// sGroup must be one of the letters in "abcdABCD"
|
||||||
|
int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
|
||||||
|
if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
|
||||||
|
}
|
||||||
|
|
||||||
|
sReturn[nReturnPos++] = '0';
|
||||||
|
sReturn[nReturnPos++] = '0';
|
||||||
|
sReturn[nReturnPos++] = '0';
|
||||||
|
|
||||||
|
sReturn[nReturnPos++] = bStatus ? '1' : '0';
|
||||||
|
sReturn[nReturnPos++] = bStatus ? '0' : '1';
|
||||||
|
|
||||||
|
sReturn[nReturnPos] = '\0';
|
||||||
|
return sReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sCodeWord a tristate code word consisting of the letter 0, 1, F
|
||||||
|
*/
|
||||||
|
void RCSwitch::sendTriState(const char* sCodeWord) {
|
||||||
|
// turn the tristate code word into the corresponding bit pattern, then send it
|
||||||
|
unsigned long code = 0;
|
||||||
|
unsigned int length = 0;
|
||||||
|
for (const char* p = sCodeWord; *p; p++) {
|
||||||
|
code <<= 2L;
|
||||||
|
switch (*p) {
|
||||||
|
case '0':
|
||||||
|
// bit pattern 00
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
// bit pattern 01
|
||||||
|
code |= 1L;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
// bit pattern 11
|
||||||
|
code |= 3L;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length += 2;
|
||||||
|
}
|
||||||
|
this->send(code, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sCodeWord a binary code word consisting of the letter 0, 1
|
||||||
|
*/
|
||||||
|
void RCSwitch::send(const char* sCodeWord) {
|
||||||
|
// turn the tristate code word into the corresponding bit pattern, then send it
|
||||||
|
unsigned long code = 0;
|
||||||
|
unsigned int length = 0;
|
||||||
|
for (const char* p = sCodeWord; *p; p++) {
|
||||||
|
code <<= 1L;
|
||||||
|
if (*p != '0')
|
||||||
|
code |= 1L;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
this->send(code, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit the first 'length' bits of the integer 'code'. The
|
||||||
|
* bits are sent from MSB to LSB, i.e., first the bit at position length-1,
|
||||||
|
* then the bit at position length-2, and so on, till finally the bit at position 0.
|
||||||
|
*/
|
||||||
|
void RCSwitch::send(unsigned long code, unsigned int length) {
|
||||||
|
if (this->nTransmitterPin == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
// make sure the receiver is disabled while we transmit
|
||||||
|
int nReceiverInterrupt_backup = nReceiverInterrupt;
|
||||||
|
if (nReceiverInterrupt_backup != -1) {
|
||||||
|
this->disableReceive();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
|
||||||
|
for (int i = length-1; i >= 0; i--) {
|
||||||
|
if (code & (1L << i))
|
||||||
|
this->transmit(protocol.one);
|
||||||
|
else
|
||||||
|
this->transmit(protocol.zero);
|
||||||
|
}
|
||||||
|
this->transmit(protocol.syncFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable transmit after sending (i.e., for inverted protocols)
|
||||||
|
digitalWrite(this->nTransmitterPin, LOW);
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
// enable receiver again if we just disabled it
|
||||||
|
if (nReceiverInterrupt_backup != -1) {
|
||||||
|
this->enableReceive(nReceiverInterrupt_backup);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit a single high-low pulse.
|
||||||
|
*/
|
||||||
|
void RCSwitch::transmit(HighLow pulses) {
|
||||||
|
uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
|
||||||
|
uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
|
||||||
|
|
||||||
|
digitalWrite(this->nTransmitterPin, firstLogicLevel);
|
||||||
|
delayMicroseconds( this->protocol.pulseLength * pulses.high);
|
||||||
|
digitalWrite(this->nTransmitterPin, secondLogicLevel);
|
||||||
|
delayMicroseconds( this->protocol.pulseLength * pulses.low);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
/**
|
||||||
|
* Enable receiving data
|
||||||
|
*/
|
||||||
|
void RCSwitch::enableReceive(int interrupt) {
|
||||||
|
this->nReceiverInterrupt = interrupt;
|
||||||
|
this->enableReceive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCSwitch::enableReceive() {
|
||||||
|
if (this->nReceiverInterrupt != -1) {
|
||||||
|
RCSwitch::nReceivedValue = 0;
|
||||||
|
RCSwitch::nReceivedBitlength = 0;
|
||||||
|
#if defined(RaspberryPi) // Raspberry Pi
|
||||||
|
wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
|
||||||
|
#else // Arduino
|
||||||
|
attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable receiving data
|
||||||
|
*/
|
||||||
|
void RCSwitch::disableReceive() {
|
||||||
|
#if not defined(RaspberryPi) // Arduino
|
||||||
|
detachInterrupt(this->nReceiverInterrupt);
|
||||||
|
#endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
|
||||||
|
this->nReceiverInterrupt = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RCSwitch::available() {
|
||||||
|
return RCSwitch::nReceivedValue != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCSwitch::resetAvailable() {
|
||||||
|
RCSwitch::nReceivedValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long RCSwitch::getReceivedValue() {
|
||||||
|
return RCSwitch::nReceivedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int RCSwitch::getReceivedBitlength() {
|
||||||
|
return RCSwitch::nReceivedBitlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int RCSwitch::getReceivedDelay() {
|
||||||
|
return RCSwitch::nReceivedDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int RCSwitch::getReceivedProtocol() {
|
||||||
|
return RCSwitch::nReceivedProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int* RCSwitch::getReceivedRawdata() {
|
||||||
|
return RCSwitch::timings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* helper function for the receiveProtocol method */
|
||||||
|
static inline unsigned int diff(int A, int B) {
|
||||||
|
return abs(A - B);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
|
||||||
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
|
const Protocol &pro = proto[p-1];
|
||||||
|
#else
|
||||||
|
Protocol pro;
|
||||||
|
memcpy_P(&pro, &proto[p-1], sizeof(Protocol));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned long code = 0;
|
||||||
|
//Assuming the longer pulse length is the pulse captured in timings[0]
|
||||||
|
const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high);
|
||||||
|
const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses;
|
||||||
|
const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100;
|
||||||
|
|
||||||
|
/* For protocols that start low, the sync period looks like
|
||||||
|
* _________
|
||||||
|
* _____________| |XXXXXXXXXXXX|
|
||||||
|
*
|
||||||
|
* |--1st dur--|-2nd dur-|-Start data-|
|
||||||
|
*
|
||||||
|
* The 3rd saved duration starts the data.
|
||||||
|
*
|
||||||
|
* For protocols that start high, the sync period looks like
|
||||||
|
*
|
||||||
|
* ______________
|
||||||
|
* | |____________|XXXXXXXXXXXXX|
|
||||||
|
*
|
||||||
|
* |-filtered out-|--1st dur--|--Start data--|
|
||||||
|
*
|
||||||
|
* The 2nd saved duration starts the data
|
||||||
|
*/
|
||||||
|
const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
|
||||||
|
|
||||||
|
for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) {
|
||||||
|
code <<= 1;
|
||||||
|
if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance &&
|
||||||
|
diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) {
|
||||||
|
// zero
|
||||||
|
} else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
|
||||||
|
diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
|
||||||
|
// one
|
||||||
|
code |= 1;
|
||||||
|
} else {
|
||||||
|
// Failed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise
|
||||||
|
RCSwitch::nReceivedValue = code;
|
||||||
|
RCSwitch::nReceivedBitlength = (changeCount - 1) / 2;
|
||||||
|
RCSwitch::nReceivedDelay = delay;
|
||||||
|
RCSwitch::nReceivedProtocol = p;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RECEIVE_ATTR RCSwitch::handleInterrupt() {
|
||||||
|
|
||||||
|
static unsigned int changeCount = 0;
|
||||||
|
static unsigned long lastTime = 0;
|
||||||
|
static unsigned int repeatCount = 0;
|
||||||
|
|
||||||
|
const long time = micros();
|
||||||
|
const unsigned int duration = time - lastTime;
|
||||||
|
|
||||||
|
if (duration > RCSwitch::nSeparationLimit) {
|
||||||
|
// A long stretch without signal level change occurred. This could
|
||||||
|
// be the gap between two transmission.
|
||||||
|
if ((repeatCount==0) || (diff(duration, RCSwitch::timings[0]) < 200)) {
|
||||||
|
// This long signal is close in length to the long signal which
|
||||||
|
// started the previously recorded timings; this suggests that
|
||||||
|
// it may indeed by a a gap between two transmissions (we assume
|
||||||
|
// here that a sender will send the signal multiple times,
|
||||||
|
// with roughly the same gap between them).
|
||||||
|
repeatCount++;
|
||||||
|
if (repeatCount == 2) {
|
||||||
|
for(unsigned int i = 1; i <= numProto; i++) {
|
||||||
|
if (receiveProtocol(i, changeCount)) {
|
||||||
|
// receive succeeded for protocol i
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repeatCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changeCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect overflow
|
||||||
|
if (changeCount >= RCSWITCH_MAX_CHANGES) {
|
||||||
|
changeCount = 0;
|
||||||
|
repeatCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RCSwitch::timings[changeCount++] = duration;
|
||||||
|
lastTime = time;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
RCSwitch - Arduino libary for remote control outlet switches
|
||||||
|
Copyright (c) 2011 Suat Özgür. All right reserved.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
- Andre Koehler / info(at)tomate-online(dot)de
|
||||||
|
- Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
|
||||||
|
- Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
|
||||||
|
- Dominik Fischer / dom_fischer(at)web(dot)de
|
||||||
|
- Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
|
||||||
|
- Max Horn / max(at)quendi(dot)de
|
||||||
|
- Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
|
||||||
|
|
||||||
|
Project home: https://github.com/sui77/rc-switch/
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#ifndef _RCSwitch_h
|
||||||
|
#define _RCSwitch_h
|
||||||
|
|
||||||
|
#if defined(ARDUINO) && ARDUINO >= 100
|
||||||
|
#include "Arduino.h"
|
||||||
|
#elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific
|
||||||
|
#include "Energia.h"
|
||||||
|
#elif defined(RPI) // Raspberry Pi
|
||||||
|
#define RaspberryPi
|
||||||
|
|
||||||
|
// Include libraries for RPi:
|
||||||
|
#include <string.h> /* memcpy */
|
||||||
|
#include <stdlib.h> /* abs */
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#elif defined(SPARK)
|
||||||
|
#include "application.h"
|
||||||
|
#else
|
||||||
|
#include "WProgram.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
// At least for the ATTiny X4/X5, receiving has to be disabled due to
|
||||||
|
// missing libm depencies (udivmodhi4)
|
||||||
|
//#if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ )
|
||||||
|
//#define RCSwitchDisableReceiving
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
// Number of maximum high/Low changes per packet.
|
||||||
|
// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync
|
||||||
|
#define RCSWITCH_MAX_CHANGES 67
|
||||||
|
|
||||||
|
class RCSwitch {
|
||||||
|
|
||||||
|
public:
|
||||||
|
RCSwitch();
|
||||||
|
|
||||||
|
void switchOn(int nGroupNumber, int nSwitchNumber);
|
||||||
|
void switchOff(int nGroupNumber, int nSwitchNumber);
|
||||||
|
void switchOn(const char* sGroup, int nSwitchNumber);
|
||||||
|
void switchOff(const char* sGroup, int nSwitchNumber);
|
||||||
|
void switchOn(char sFamily, int nGroup, int nDevice);
|
||||||
|
void switchOff(char sFamily, int nGroup, int nDevice);
|
||||||
|
void switchOn(const char* sGroup, const char* sDevice);
|
||||||
|
void switchOff(const char* sGroup, const char* sDevice);
|
||||||
|
void switchOn(char sGroup, int nDevice);
|
||||||
|
void switchOff(char sGroup, int nDevice);
|
||||||
|
|
||||||
|
void sendTriState(const char* sCodeWord);
|
||||||
|
void send(unsigned long code, unsigned int length);
|
||||||
|
void send(const char* sCodeWord);
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
void enableReceive(int interrupt);
|
||||||
|
void enableReceive();
|
||||||
|
void disableReceive();
|
||||||
|
bool available();
|
||||||
|
void resetAvailable();
|
||||||
|
|
||||||
|
unsigned long getReceivedValue();
|
||||||
|
unsigned int getReceivedBitlength();
|
||||||
|
unsigned int getReceivedDelay();
|
||||||
|
unsigned int getReceivedProtocol();
|
||||||
|
unsigned int* getReceivedRawdata();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void enableTransmit(int nTransmitterPin);
|
||||||
|
void disableTransmit();
|
||||||
|
void setPulseLength(int nPulseLength);
|
||||||
|
void setRepeatTransmit(int nRepeatTransmit);
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
void setReceiveTolerance(int nPercent);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description of a single pule, which consists of a high signal
|
||||||
|
* whose duration is "high" times the base pulse length, followed
|
||||||
|
* by a low signal lasting "low" times the base pulse length.
|
||||||
|
* Thus, the pulse overall lasts (high+low)*pulseLength
|
||||||
|
*/
|
||||||
|
struct HighLow {
|
||||||
|
uint8_t high;
|
||||||
|
uint8_t low;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "protocol" describes how zero and one bits are encoded into high/low
|
||||||
|
* pulses.
|
||||||
|
*/
|
||||||
|
struct Protocol {
|
||||||
|
/** base pulse length in microseconds, e.g. 350 */
|
||||||
|
uint16_t pulseLength;
|
||||||
|
|
||||||
|
HighLow syncFactor;
|
||||||
|
HighLow zero;
|
||||||
|
HighLow one;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, interchange high and low logic levels in all transmissions.
|
||||||
|
*
|
||||||
|
* By default, RCSwitch assumes that any signals it sends or receives
|
||||||
|
* can be broken down into pulses which start with a high signal level,
|
||||||
|
* followed by a a low signal level. This is e.g. the case for the
|
||||||
|
* popular PT 2260 encoder chip, and thus many switches out there.
|
||||||
|
*
|
||||||
|
* But some devices do it the other way around, and start with a low
|
||||||
|
* signal level, followed by a high signal level, e.g. the HT6P20B. To
|
||||||
|
* accommodate this, one can set invertedSignal to true, which causes
|
||||||
|
* RCSwitch to change how it interprets any HighLow struct FOO: It will
|
||||||
|
* then assume transmissions start with a low signal lasting
|
||||||
|
* FOO.high*pulseLength microseconds, followed by a high signal lasting
|
||||||
|
* FOO.low*pulseLength microseconds.
|
||||||
|
*/
|
||||||
|
bool invertedSignal;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setProtocol(Protocol protocol);
|
||||||
|
void setProtocol(int nProtocol);
|
||||||
|
void setProtocol(int nProtocol, int nPulseLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus);
|
||||||
|
char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus);
|
||||||
|
char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus);
|
||||||
|
char* getCodeWordD(char group, int nDevice, bool bStatus);
|
||||||
|
void transmit(HighLow pulses);
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
static void handleInterrupt();
|
||||||
|
static bool receiveProtocol(const int p, unsigned int changeCount);
|
||||||
|
int nReceiverInterrupt;
|
||||||
|
#endif
|
||||||
|
int nTransmitterPin;
|
||||||
|
int nRepeatTransmit;
|
||||||
|
|
||||||
|
Protocol protocol;
|
||||||
|
|
||||||
|
#if not defined( RCSwitchDisableReceiving )
|
||||||
|
static int nReceiveTolerance;
|
||||||
|
volatile static unsigned long nReceivedValue;
|
||||||
|
volatile static unsigned int nReceivedBitlength;
|
||||||
|
volatile static unsigned int nReceivedDelay;
|
||||||
|
volatile static unsigned int nReceivedProtocol;
|
||||||
|
const static unsigned int nSeparationLimit;
|
||||||
|
/*
|
||||||
|
* timings[0] contains sync timing, followed by a number of bits
|
||||||
|
*/
|
||||||
|
static unsigned int timings[RCSWITCH_MAX_CHANGES];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
# rc-switch
|
||||||
|
[](https://www.ardu-badge.com/rc-switch)
|
||||||
|
[](https://travis-ci.org/sui77/rc-switch)
|
||||||
|
|
||||||
|
Use your Arduino or [Raspberry Pi](https://github.com/r10r/rcswitch-pi) to operate remote radio controlled devices
|
||||||
|
|
||||||
|
## Download
|
||||||
|
https://github.com/sui77/rc-switch/releases/latest
|
||||||
|
|
||||||
|
rc-switch is also listed in the arduino library manager.
|
||||||
|
|
||||||
|
## Wiki
|
||||||
|
https://github.com/sui77/rc-switch/wiki
|
||||||
|
|
||||||
|
## Info
|
||||||
|
### Send RC codes
|
||||||
|
|
||||||
|
Use your Arduino or Raspberry Pi to operate remote radio controlled devices.
|
||||||
|
This will most likely work with all popular low cost power outlet sockets. If
|
||||||
|
yours doesn't work, you might need to adjust the pulse length.
|
||||||
|
|
||||||
|
All you need is a Arduino or Raspberry Pi, a 315/433MHz AM transmitter and one
|
||||||
|
or more devices with one of the supported chipsets:
|
||||||
|
|
||||||
|
- SC5262 / SC5272
|
||||||
|
- HX2262 / HX2272
|
||||||
|
- PT2262 / PT2272
|
||||||
|
- EV1527 / RT1527 / FP1527 / HS1527
|
||||||
|
- Intertechno outlets
|
||||||
|
- HT6P20X
|
||||||
|
|
||||||
|
### Receive and decode RC codes
|
||||||
|
|
||||||
|
Find out what codes your remote is sending. Use your remote to control your
|
||||||
|
Arduino.
|
||||||
|
|
||||||
|
All you need is an Arduino, a 315/433MHz AM receiver (altough there is no
|
||||||
|
instruction yet, yes it is possible to hack an existing device) and a remote
|
||||||
|
hand set.
|
||||||
|
|
||||||
|
For the Raspberry Pi, clone the https://github.com/ninjablocks/433Utils project to
|
||||||
|
compile a sniffer tool and transmission commands.
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Example for receiving
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
|
||||||
|
If you want to visualize a telegram copy the raw data and
|
||||||
|
paste it into http://test.sui.li/oszi/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (mySwitch.available()) {
|
||||||
|
output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol());
|
||||||
|
mySwitch.resetAvailable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
static const char* bin2tristate(const char* bin);
|
||||||
|
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength);
|
||||||
|
|
||||||
|
void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) {
|
||||||
|
|
||||||
|
const char* b = dec2binWzerofill(decimal, length);
|
||||||
|
Serial.print("Decimal: ");
|
||||||
|
Serial.print(decimal);
|
||||||
|
Serial.print(" (");
|
||||||
|
Serial.print( length );
|
||||||
|
Serial.print("Bit) Binary: ");
|
||||||
|
Serial.print( b );
|
||||||
|
Serial.print(" Tri-State: ");
|
||||||
|
Serial.print( bin2tristate( b) );
|
||||||
|
Serial.print(" PulseLength: ");
|
||||||
|
Serial.print(delay);
|
||||||
|
Serial.print(" microseconds");
|
||||||
|
Serial.print(" Protocol: ");
|
||||||
|
Serial.println(protocol);
|
||||||
|
|
||||||
|
Serial.print("Raw data: ");
|
||||||
|
for (unsigned int i=0; i<= length*2; i++) {
|
||||||
|
Serial.print(raw[i]);
|
||||||
|
Serial.print(",");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* bin2tristate(const char* bin) {
|
||||||
|
static char returnValue[50];
|
||||||
|
int pos = 0;
|
||||||
|
int pos2 = 0;
|
||||||
|
while (bin[pos]!='\0' && bin[pos+1]!='\0') {
|
||||||
|
if (bin[pos]=='0' && bin[pos+1]=='0') {
|
||||||
|
returnValue[pos2] = '0';
|
||||||
|
} else if (bin[pos]=='1' && bin[pos+1]=='1') {
|
||||||
|
returnValue[pos2] = '1';
|
||||||
|
} else if (bin[pos]=='0' && bin[pos+1]=='1') {
|
||||||
|
returnValue[pos2] = 'F';
|
||||||
|
} else {
|
||||||
|
return "not applicable";
|
||||||
|
}
|
||||||
|
pos = pos+2;
|
||||||
|
pos2++;
|
||||||
|
}
|
||||||
|
returnValue[pos2] = '\0';
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
|
||||||
|
static char bin[64];
|
||||||
|
unsigned int i=0;
|
||||||
|
|
||||||
|
while (Dec > 0) {
|
||||||
|
bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
|
||||||
|
Dec = Dec >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j< bitLength; j++) {
|
||||||
|
if (j >= bitLength - i) {
|
||||||
|
bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
|
||||||
|
} else {
|
||||||
|
bin[j] = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bin[bitLength] = '\0';
|
||||||
|
|
||||||
|
return bin;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
Simple example for receiving
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (mySwitch.available()) {
|
||||||
|
|
||||||
|
Serial.print("Received ");
|
||||||
|
Serial.print( mySwitch.getReceivedValue() );
|
||||||
|
Serial.print(" / ");
|
||||||
|
Serial.print( mySwitch.getReceivedBitlength() );
|
||||||
|
Serial.print("bit ");
|
||||||
|
Serial.print("Protocol: ");
|
||||||
|
Serial.println( mySwitch.getReceivedProtocol() );
|
||||||
|
|
||||||
|
mySwitch.resetAvailable();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
Example for different sending methods
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// Transmitter is connected to Arduino Pin #10
|
||||||
|
mySwitch.enableTransmit(10);
|
||||||
|
|
||||||
|
// Optional set protocol (default is 1, will work for most outlets)
|
||||||
|
// mySwitch.setProtocol(2);
|
||||||
|
|
||||||
|
// Optional set pulse length.
|
||||||
|
// mySwitch.setPulseLength(320);
|
||||||
|
|
||||||
|
// Optional set number of transmission repetitions.
|
||||||
|
// mySwitch.setRepeatTransmit(15);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
/* See Example: TypeA_WithDIPSwitches */
|
||||||
|
mySwitch.switchOn("11111", "00010");
|
||||||
|
delay(1000);
|
||||||
|
mySwitch.switchOff("11111", "00010");
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
/* Same switch as above, but using decimal code */
|
||||||
|
mySwitch.send(5393, 24);
|
||||||
|
delay(1000);
|
||||||
|
mySwitch.send(5396, 24);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
/* Same switch as above, but using binary code */
|
||||||
|
mySwitch.send("000000000001010100010001");
|
||||||
|
delay(1000);
|
||||||
|
mySwitch.send("000000000001010100010100");
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
/* Same switch as above, but tri-state code */
|
||||||
|
mySwitch.sendTriState("00000FFF0F0F");
|
||||||
|
delay(1000);
|
||||||
|
mySwitch.sendTriState("00000FFF0FF0");
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
delay(20000);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
Example for outlets which are configured with a 10 pole DIP switch.
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// Transmitter is connected to Arduino Pin #10
|
||||||
|
mySwitch.enableTransmit(10);
|
||||||
|
|
||||||
|
// Optional set pulse length.
|
||||||
|
// mySwitch.setPulseLength(320);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Switch on:
|
||||||
|
// The first parameter represents the setting of the first 5 DIP switches.
|
||||||
|
// In this example it's ON-ON-OFF-OFF-ON.
|
||||||
|
//
|
||||||
|
// The second parameter represents the setting of the last 5 DIP switches.
|
||||||
|
// In this example the last 5 DIP switches are OFF-ON-OFF-ON-OFF.
|
||||||
|
mySwitch.switchOn("11001", "01010");
|
||||||
|
|
||||||
|
// Wait a second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// Switch off
|
||||||
|
mySwitch.switchOff("11001", "01010");
|
||||||
|
|
||||||
|
// Wait another second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
This is a minimal sketch without using the library at all but only works for
|
||||||
|
the 10 pole dip switch sockets. It saves a lot of memory and thus might be
|
||||||
|
very useful to use with ATTinys :)
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
int RCLpin = 7;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pinMode(RCLpin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
RCLswitch(0b010001000001); // DIPs an Steckdose: 0100010000 An:01
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
RCLswitch(0b010001000010); // DIPs an Steckdose: 0100010000 Aus:10
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCLswitch(uint16_t code) {
|
||||||
|
for (int nRepeat=0; nRepeat<6; nRepeat++) {
|
||||||
|
for (int i=4; i<16; i++) {
|
||||||
|
RCLtransmit(1,3);
|
||||||
|
if (((code << (i-4)) & 2048) > 0) {
|
||||||
|
RCLtransmit(1,3);
|
||||||
|
} else {
|
||||||
|
RCLtransmit(3,1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RCLtransmit(1,31);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RCLtransmit(int nHighPulses, int nLowPulses) {
|
||||||
|
digitalWrite(RCLpin, HIGH);
|
||||||
|
delayMicroseconds( 350 * nHighPulses);
|
||||||
|
digitalWrite(RCLpin, LOW);
|
||||||
|
delayMicroseconds( 350 * nLowPulses);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
Example for outlets which are configured with two rotary/sliding switches.
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// Transmitter is connected to Arduino Pin #10
|
||||||
|
mySwitch.enableTransmit(10);
|
||||||
|
|
||||||
|
// Optional set pulse length.
|
||||||
|
// mySwitch.setPulseLength(320);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Switch on:
|
||||||
|
// The first parameter represents the setting of the first rotary switch.
|
||||||
|
// In this example it's switched to "1" or "A" or "I".
|
||||||
|
//
|
||||||
|
// The second parameter represents the setting of the second rotary switch.
|
||||||
|
// In this example it's switched to "4" or "D" or "IV".
|
||||||
|
mySwitch.switchOn(1, 4);
|
||||||
|
|
||||||
|
// Wait a second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// Switch off
|
||||||
|
mySwitch.switchOff(1, 4);
|
||||||
|
|
||||||
|
// Wait another second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
Example for Intertechno outlets
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// Transmitter is connected to Arduino Pin #10
|
||||||
|
mySwitch.enableTransmit(10);
|
||||||
|
|
||||||
|
// Optional set pulse length.
|
||||||
|
// mySwitch.setPulseLength(320);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Switch on:
|
||||||
|
// The first parameter represents the familycode (a, b, c, ... f)
|
||||||
|
// The second parameter represents the group number
|
||||||
|
// The third parameter represents the device number
|
||||||
|
//
|
||||||
|
// In this example it's family 'b', group #3, device #2
|
||||||
|
mySwitch.switchOn('b', 3, 2);
|
||||||
|
|
||||||
|
// Wait a second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// Switch off
|
||||||
|
mySwitch.switchOff('b', 3, 2);
|
||||||
|
|
||||||
|
// Wait another second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
Example for REV outlets (e.g. 8342L)
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
|
||||||
|
Need help? http://forum.ardumote.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
|
||||||
|
// Transmitter is connected to Arduino Pin #10
|
||||||
|
mySwitch.enableTransmit(10);
|
||||||
|
|
||||||
|
// set pulse length.
|
||||||
|
mySwitch.setPulseLength(360);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
// Switch on:
|
||||||
|
// The first parameter represents the channel (a, b, c, d)
|
||||||
|
// The second parameter represents the device number
|
||||||
|
//
|
||||||
|
// In this example it's family 'd', device #2
|
||||||
|
mySwitch.switchOn('d', 2);
|
||||||
|
|
||||||
|
// Wait a second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// Switch off
|
||||||
|
mySwitch.switchOff('d', 2);
|
||||||
|
|
||||||
|
// Wait another second
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
A simple RCSwitch/Ethernet/Webserver demo
|
||||||
|
|
||||||
|
https://github.com/sui77/rc-switch/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <Ethernet.h>
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
|
||||||
|
// Ethernet configuration
|
||||||
|
uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC Address
|
||||||
|
uint8_t ip[] = { 192,168,0, 2 }; // IP Address
|
||||||
|
EthernetServer server(80); // Server Port 80
|
||||||
|
|
||||||
|
// RCSwitch configuration
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
int RCTransmissionPin = 7;
|
||||||
|
|
||||||
|
// More to do...
|
||||||
|
// You should also modify the processCommand() and
|
||||||
|
// httpResponseHome() functions to fit your needs.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup
|
||||||
|
*/
|
||||||
|
void setup() {
|
||||||
|
Ethernet.begin(mac, ip);
|
||||||
|
server.begin();
|
||||||
|
mySwitch.enableTransmit( RCTransmissionPin );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop
|
||||||
|
*/
|
||||||
|
void loop() {
|
||||||
|
char* command = httpServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command dispatcher
|
||||||
|
*/
|
||||||
|
void processCommand(char* command) {
|
||||||
|
if (strcmp(command, "1-on") == 0) {
|
||||||
|
mySwitch.switchOn(1,1);
|
||||||
|
} else if (strcmp(command, "1-off") == 0) {
|
||||||
|
mySwitch.switchOff(1,1);
|
||||||
|
} else if (strcmp(command, "2-on") == 0) {
|
||||||
|
mySwitch.switchOn(1,2);
|
||||||
|
} else if (strcmp(command, "2-off") == 0) {
|
||||||
|
mySwitch.switchOff(1,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Response with homepage
|
||||||
|
*/
|
||||||
|
void httpResponseHome(EthernetClient c) {
|
||||||
|
c.println("HTTP/1.1 200 OK");
|
||||||
|
c.println("Content-Type: text/html");
|
||||||
|
c.println();
|
||||||
|
c.println("<html>");
|
||||||
|
c.println("<head>");
|
||||||
|
c.println( "<title>RCSwitch Webserver Demo</title>");
|
||||||
|
c.println( "<style>");
|
||||||
|
c.println( "body { font-family: Arial, sans-serif; font-size:12px; }");
|
||||||
|
c.println( "</style>");
|
||||||
|
c.println("</head>");
|
||||||
|
c.println("<body>");
|
||||||
|
c.println( "<h1>RCSwitch Webserver Demo</h1>");
|
||||||
|
c.println( "<ul>");
|
||||||
|
c.println( "<li><a href=\"./?1-on\">Switch #1 on</a></li>");
|
||||||
|
c.println( "<li><a href=\"./?1-off\">Switch #1 off</a></li>");
|
||||||
|
c.println( "</ul>");
|
||||||
|
c.println( "<ul>");
|
||||||
|
c.println( "<li><a href=\"./?2-on\">Switch #2 on</a></li>");
|
||||||
|
c.println( "<li><a href=\"./?2-off\">Switch #2 off</a></li>");
|
||||||
|
c.println( "</ul>");
|
||||||
|
c.println( "<hr>");
|
||||||
|
c.println( "<a href=\"https://github.com/sui77/rc-switch/\">https://github.com/sui77/rc-switch/</a>");
|
||||||
|
c.println("</body>");
|
||||||
|
c.println("</html>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Redirect to homepage
|
||||||
|
*/
|
||||||
|
void httpResponseRedirect(EthernetClient c) {
|
||||||
|
c.println("HTTP/1.1 301 Found");
|
||||||
|
c.println("Location: /");
|
||||||
|
c.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Response 414 error
|
||||||
|
* Command must not be longer than 30 characters
|
||||||
|
**/
|
||||||
|
void httpResponse414(EthernetClient c) {
|
||||||
|
c.println("HTTP/1.1 414 Request URI too long");
|
||||||
|
c.println("Content-Type: text/plain");
|
||||||
|
c.println();
|
||||||
|
c.println("414 Request URI too long");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process HTTP requests, parse first request header line and
|
||||||
|
* call processCommand with GET query string (everything after
|
||||||
|
* the ? question mark in the URL).
|
||||||
|
*/
|
||||||
|
char* httpServer() {
|
||||||
|
EthernetClient client = server.available();
|
||||||
|
if (client) {
|
||||||
|
char sReturnCommand[32];
|
||||||
|
int nCommandPos=-1;
|
||||||
|
sReturnCommand[0] = '\0';
|
||||||
|
while (client.connected()) {
|
||||||
|
if (client.available()) {
|
||||||
|
char c = client.read();
|
||||||
|
if ((c == '\n') || (c == ' ' && nCommandPos>-1)) {
|
||||||
|
sReturnCommand[nCommandPos] = '\0';
|
||||||
|
if (strcmp(sReturnCommand, "\0") == 0) {
|
||||||
|
httpResponseHome(client);
|
||||||
|
} else {
|
||||||
|
processCommand(sReturnCommand);
|
||||||
|
httpResponseRedirect(client);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nCommandPos>-1) {
|
||||||
|
sReturnCommand[nCommandPos++] = c;
|
||||||
|
}
|
||||||
|
if (c == '?' && nCommandPos == -1) {
|
||||||
|
nCommandPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nCommandPos > 30) {
|
||||||
|
httpResponse414(client);
|
||||||
|
sReturnCommand[0] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nCommandPos!=-1) {
|
||||||
|
sReturnCommand[nCommandPos] = '\0';
|
||||||
|
}
|
||||||
|
// give the web browser time to receive the data
|
||||||
|
delay(1);
|
||||||
|
client.stop();
|
||||||
|
|
||||||
|
return sReturnCommand;
|
||||||
|
}
|
||||||
|
return '\0';
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For RCSwitch
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
RCSwitch KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
##########
|
||||||
|
#SENDS Begin
|
||||||
|
##########
|
||||||
|
switchOn KEYWORD2
|
||||||
|
switchOff KEYWORD2
|
||||||
|
sendTriState KEYWORD2
|
||||||
|
send KEYWORD2
|
||||||
|
##########
|
||||||
|
#SENDS End
|
||||||
|
##########
|
||||||
|
|
||||||
|
##########
|
||||||
|
#RECEIVE Begin
|
||||||
|
##########
|
||||||
|
enableReceive KEYWORD2
|
||||||
|
disableReceive KEYWORD2
|
||||||
|
available KEYWORD2
|
||||||
|
resetAvailable KEYWORD2
|
||||||
|
setReceiveTolerance KEYWORD2
|
||||||
|
getReceivedValue KEYWORD2
|
||||||
|
getReceivedBitlength KEYWORD2
|
||||||
|
getReceivedDelay KEYWORD2
|
||||||
|
getReceivedProtocol KEYWORD2
|
||||||
|
getReceivedRawdata KEYWORD2
|
||||||
|
##########
|
||||||
|
#RECEIVE End
|
||||||
|
##########
|
||||||
|
|
||||||
|
##########
|
||||||
|
#OTHERS Begin
|
||||||
|
##########
|
||||||
|
enableTransmit KEYWORD2
|
||||||
|
disableTransmit KEYWORD2
|
||||||
|
setPulseLength KEYWORD2
|
||||||
|
setProtocol KEYWORD2
|
||||||
|
setRepeatTransmit KEYWORD2
|
||||||
|
##########
|
||||||
|
#OTHERS End
|
||||||
|
##########
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "rc-switch",
|
||||||
|
"description": "Use your Arduino or Raspberry Pi to operate remote radio controlled devices",
|
||||||
|
"keywords": "rf, radio, wireless",
|
||||||
|
"authors":
|
||||||
|
{
|
||||||
|
"name": "Suat Ozgur"
|
||||||
|
},
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/sui77/rc-switch.git"
|
||||||
|
},
|
||||||
|
"version": "2.6.4",
|
||||||
|
"frameworks": [
|
||||||
|
"arduino",
|
||||||
|
"energia",
|
||||||
|
"wiringpi"
|
||||||
|
],
|
||||||
|
"platforms": "*"
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
name=rc-switch
|
||||||
|
version=2.6.4
|
||||||
|
author=sui77
|
||||||
|
maintainer=sui77,fingolfin <noreply@sui.li>
|
||||||
|
sentence=Operate 433/315Mhz devices.
|
||||||
|
paragraph=Use your Arduino, ESP8266/ESP32 or Raspberry Pi to operate remote radio controlled devices. This will most likely work with all popular low cost power outlet sockets.
|
||||||
|
category=Device Control
|
||||||
|
url=https://github.com/sui77/rc-switch
|
||||||
|
architectures=avr,esp8266,esp32,stm32
|
||||||
|
includes=RCSwitch.h
|
|
@ -0,0 +1,42 @@
|
||||||
|
[platformio]
|
||||||
|
default_envs = nanoatmega328
|
||||||
|
|
||||||
|
[env:nanoatmega328]
|
||||||
|
platform = atmelavr
|
||||||
|
board = nanoatmega328
|
||||||
|
framework = arduino
|
||||||
|
board_build.f_cpu = 16000000L
|
||||||
|
lib_deps =
|
||||||
|
robtillaart/DHTStable
|
||||||
|
targets = upload, monitor
|
||||||
|
upload_port = /dev/ttyUSB0
|
||||||
|
monitor_port = /dev/ttyUSB0
|
||||||
|
monitor_speed = 9600
|
||||||
|
monitor_filters =
|
||||||
|
default ; Remove typical terminal control codes from input
|
||||||
|
time ; Add timestamp with milliseconds for each new line
|
||||||
|
; log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
|
||||||
|
|
||||||
|
|
||||||
|
[env:tiny85]
|
||||||
|
platform = atmelavr
|
||||||
|
framework = arduino
|
||||||
|
#board = digispark-tiny
|
||||||
|
board = attiny85
|
||||||
|
board_build.f_cpu = 8000000L
|
||||||
|
lib_deps =
|
||||||
|
robtillaart/DHTStable
|
||||||
|
upload_protocol = stk500v1
|
||||||
|
upload_flags =
|
||||||
|
-P$UPLOAD_PORT
|
||||||
|
-b$UPLOAD_SPEED
|
||||||
|
targets = upload, monitor
|
||||||
|
upload_speed = 19200
|
||||||
|
upload_port = /dev/ttyUSB0
|
||||||
|
monitor_port = /dev/ttyUSB1
|
||||||
|
monitor_speed = 9600
|
||||||
|
monitor_filters =
|
||||||
|
default ; Remove typical terminal control codes from input
|
||||||
|
time ; Add timestamp with milliseconds for each new line
|
||||||
|
; log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#define LOGGER 1 // Enable logger on Serial 1 : enable 2 : disable
|
||||||
|
#define SEND_DELAY 120L // Delay between each sensor transmitting / "L" is for the long type (mandatory)
|
|
@ -0,0 +1,160 @@
|
||||||
|
#include <RCSwitch.h>
|
||||||
|
//#include <Oregon_TM.h>
|
||||||
|
#include <NexusTX.h>
|
||||||
|
#include <SensorTransmitter.h>
|
||||||
|
#include <DHTStable.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#if defined(ARDUINO_AVR_NANO)
|
||||||
|
#include "pins-nano.h"
|
||||||
|
#elif defined(ARDUINO_AVR_ATTINYX5)
|
||||||
|
#include "pins-attiny85.h"
|
||||||
|
#else
|
||||||
|
#error "Pins undef for this core"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
RCSwitch mySwitch = RCSwitch();
|
||||||
|
NexusTX transmitter(PIN_SEND);
|
||||||
|
//Oregon_TM transmitter(PIN_SEND);
|
||||||
|
//ThermoHygroTransmitter transmitter(PIN_SEND, SENSORID, 2);
|
||||||
|
|
||||||
|
DHTStable DHT;
|
||||||
|
|
||||||
|
bool sensor_enabled = false;
|
||||||
|
//bool output_enabled = false;
|
||||||
|
bool output_state = false;
|
||||||
|
unsigned long lastsend = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
pinMode(PIN_OUTPUT, OUTPUT);
|
||||||
|
digitalWrite(PIN_OUTPUT, LOW);
|
||||||
|
//delay(5000);
|
||||||
|
if(LOGGER) {
|
||||||
|
Serial.begin(9600);
|
||||||
|
#if defined(ARDUINO_AVR_ATTINYX5)
|
||||||
|
// Disable RX (free port PB1)
|
||||||
|
ACSR &=~(1<<ACIE);
|
||||||
|
ACSR |=~(1<<ACD);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
LogS("Hello");
|
||||||
|
Logln();
|
||||||
|
|
||||||
|
//sensor_enabled = true;
|
||||||
|
if(DHT.read22(PIN_DHT) == DHTLIB_OK) { sensor_enabled = true; LogS("DHT detected"); Logln(); } else { LogS("No DHT"); Logln(); }
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
|
||||||
|
//THGN132
|
||||||
|
// Model for Oregon_TM only
|
||||||
|
//transmitter.setType(THGN132);
|
||||||
|
//transmitter.setType(THGR810); //preferred
|
||||||
|
//transmitter.setType(RTGN318);
|
||||||
|
//transmitter.setType(BTHGN129);
|
||||||
|
//transmitter.setType(BTHR968);
|
||||||
|
|
||||||
|
transmitter.setChannel(0);
|
||||||
|
transmitter.setId(SENSORID);
|
||||||
|
transmitter.setBatteryFlag(1);
|
||||||
|
//transmitter.setComfort(24.2, 30);
|
||||||
|
|
||||||
|
mySwitch.enableReceive(0); // Receiver on pin INT0
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogS(const char* logstr)
|
||||||
|
{
|
||||||
|
if(LOGGER) {
|
||||||
|
Serial.print(logstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogI(long unsigned int logint)
|
||||||
|
{
|
||||||
|
if(LOGGER) {
|
||||||
|
Serial.print(logint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void LogF(float logfloat)
|
||||||
|
{
|
||||||
|
if(LOGGER) {
|
||||||
|
Serial.print(logfloat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Logln()
|
||||||
|
{
|
||||||
|
if(LOGGER) {
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (mySwitch.available()) {
|
||||||
|
|
||||||
|
unsigned long recvvalue = mySwitch.getReceivedValue();
|
||||||
|
|
||||||
|
/*
|
||||||
|
LogS("Received ");
|
||||||
|
LogI(recvvalue);
|
||||||
|
LogS(" / ");
|
||||||
|
LogI(mySwitch.getReceivedBitlength());
|
||||||
|
LogS("bit ");
|
||||||
|
LogS("Protocol: ");
|
||||||
|
LogI(mySwitch.getReceivedProtocol());
|
||||||
|
Logln();
|
||||||
|
*/
|
||||||
|
switch (recvvalue) {
|
||||||
|
case OUTPUTCODE_ON:
|
||||||
|
if(output_state == false)
|
||||||
|
{
|
||||||
|
output_state = true;
|
||||||
|
digitalWrite(PIN_OUTPUT, HIGH);
|
||||||
|
LogS("Output ON");
|
||||||
|
Logln();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OUTPUTCODE_OFF:
|
||||||
|
if(output_state == true)
|
||||||
|
{
|
||||||
|
output_state = false;
|
||||||
|
digitalWrite(PIN_OUTPUT, LOW);
|
||||||
|
LogS("Output OFF");
|
||||||
|
Logln();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mySwitch.resetAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sensor_enabled == true) {
|
||||||
|
unsigned long curmillis = millis();
|
||||||
|
if((lastsend == 0) || (curmillis > (lastsend + (SEND_DELAY*1000))) || (curmillis < lastsend)) {
|
||||||
|
lastsend = curmillis;
|
||||||
|
mySwitch.disableReceive();
|
||||||
|
if(DHT.read22(PIN_DHT) == DHTLIB_OK)
|
||||||
|
{
|
||||||
|
LogS("Send ");
|
||||||
|
LogS("Temperature: ");
|
||||||
|
LogF(DHT.getTemperature());
|
||||||
|
LogS(" Humidity: ");
|
||||||
|
LogF(DHT.getHumidity());
|
||||||
|
Logln();
|
||||||
|
transmitter.setTemperature(DHT.getTemperature()); // -49.9C...+69.9C
|
||||||
|
transmitter.setHumidity(lround(DHT.getHumidity())); // 2...98%
|
||||||
|
transmitter.SendPacket();
|
||||||
|
//transmitter.sendTempHumi(lround(DHT.getTemperature()*10), lround(DHT.getHumidity()));
|
||||||
|
} else {
|
||||||
|
LogS("DHT Error");
|
||||||
|
Logln();
|
||||||
|
}
|
||||||
|
mySwitch.enableReceive(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#define PIN_SEND 3
|
||||||
|
#define PIN_OUTPUT 1
|
||||||
|
#define SENSORID 12
|
||||||
|
#define PIN_DHT 4
|
||||||
|
|
||||||
|
#define OUTPUTCODE_OFF 5312788
|
||||||
|
#define OUTPUTCODE_ON 5312789
|
|
@ -0,0 +1,7 @@
|
||||||
|
#define PIN_SEND 4 // Transmitter PIN
|
||||||
|
#define PIN_OUTPUT 3 // Output PIN
|
||||||
|
#define SENSORID 11 // Sensor ID in the 433Mhz protocol
|
||||||
|
#define PIN_DHT 5 // Sensor (DHT22) pin
|
||||||
|
|
||||||
|
#define OUTPUTCODE_OFF 1118484 // Code receive for put the output off / {'cmd':'rcsend', 'value': 1118484}
|
||||||
|
#define OUTPUTCODE_ON 1118485 // Code receive for put the output on / {'cmd':'rcsend', 'value': 1118485}
|
Loading…
Reference in New Issue