家庭用エアコンまたはリモートコントロールのリバースエンジニアリング用のIRコントローラー

ごあいさつ、親愛なるhabrachitateli! この最初の記事では、研究とベストプラクティスを共有したいと考えました。 アパートにエアコンがあるので、家にいないときにエアコンを制御する必要があると感じました。 コテージまたは仕事から戻ってエアコンをオンにすると、熱が収まるまでしばらく待つ必要があります。 そして、私はすでに簡単なクールネスに来たいです。

「コンディショニングをリモートでオンにすることは可能でしょう...」-私は思いました。





だから、私はパナソニックのCS-XE9DKE分割システムを持っています。 エアコンを制御するというアイデアは、「独自の」IRリモートコントロールを作成することになりました。 それを「IRコントローラー」と呼びましょう。 そして、コントローラー自体を制御することは10番目のタスクです。 そして、それはアプリケーションの特定の場所に依存します。 たとえば、ホームサーバーからWizFi200経由で管理する方が便利です(リーズナブルな価格で入手するだけでは問題があります)。 両親に-SMSを(SIM900に)コントローラー番号に送信する。 他のオプションも可能です。 しかし、これは私が話したかった主なものではありません。



リバースエンジニアリング



では、ネイティブのリモートコントロールはどのようにコマンドを送信しますか? TSOP17XX IRレシーバーを使用して、リモートコントロールからのデータストリームの分析を開始しました。 リモートコントロールは2つのパッケージを短いポーズで送信することがわかりました。 最初はタイトル、2番目はチームです。 見出しは常に同じでした。



既存の赤外線信号コーディングシステム(RC5、RC6、NEC、JVCなど)に精通すると、原理は似ていますが、ここで何か他のものが適用されていることが明らかになりました。



シンガルは次のとおりです。

(アクティブレベル-低)



画像



(たとえば、マイクロ秒単位の時間などのビット値)



最初にパイロット信号があり、その後に約半分の2番目のパイロット信号(一時停止)が続き、その後に最初のパイロットビットより約8倍短い開始ビットが続きます。 次に、ビットストリームが始まります。 1ビットは、一時停止の期間(高レベル)でエンコードされます。 一時停止が1つの場合はゼロ、一時停止が3つの場合は1です。

ボタンを押すだけで、リモートはそのようなパッケージを2つ送信します。 最初はタイトル、2番目はチームです。 送信間の一時停止は約10ミリ秒です。



したがって、ヘッダーには64ビット、つまり8バイトが含まれます。 下位ビットが最初に来ます。



ヘッダーデータストリームは次のとおりです。



0100000000000100000001110010000000000000000000000000000000000001100000

またはバイト(HEX):02 20 E0 40 00 00 00 06



最後のバイトは以前のすべてのチェックサムであることに注意してください。



今、リモート自体に少し気を散らす。 リモコンには次のボタンがあります。



現在の時間、オンおよびオフタイマーを設定するためのボタンもあります(個別に)。



他と異なる3つのボタンは次のとおりです。



ポイントは、これらのボタンがすべての設定を送信するのではなく、特定のモードをオン/オフにすることです。 つまり これら3つのモードは、エアコンのどの状態でもオン/オフを切り替えることができます。



転送プロトコルに戻りましょう。 すべてのチームの前には見出しがあります。

ヘッダーバイト:02 20 E0 40 00 00 00 06

次は、チームの2番目の前提です。

3つの特別なボタンのコマンド:

イオン:02 20 E0 04 80 48 33 01

オキシグ:02 20 E0 04 80 50 33 09

静か:02 20 E0 04 80 81 33 3A

ヘッダーのように、最後のバイトはチェックサムです。



ただし、他のすべてのボタンは、すべての設定を含むパケットを一度に送信します。 また、このパッケージの形式は次のとおりです。



ビットストリーム:

0100000000000100000001110010000000000000PNF1mmm00ccccc0000000001vvvvFFFF

hhhh0000nnnnnnnnnnnXfffffffffffY000010000000000010000000tttttttttt00000sssssssss



フィールドを順番に解読する:

P-1 ON / OFFボタンが押されたとき。 他のボタンを押すと、ここに0が表示されます。

N-オンタイマーが設定されている場合は1

F-オフタイマーが設定されている場合は1

mmm-モード。 自動-0、熱-4、冷却-3、乾燥-2、ファン-6

ccccc-温度。 16から30

vvvvは垂直方向です。 自動-15、1-天井へ、... 5-床へ。

FFFF-ファン速度。 自動-10、F1-3、F2-4、F3-5、F4-6、F5-7

hhhhは水平方向です。 自動-13、| | -6、/ /-9、/ | -10、| \-11、\ \-12

nnnnnnnnnnnは時間どおりです。 1日の分数。 (例:16:00 = 960)

X-タイマーセット/リセットボタンが押された場合は1

fffffffffff-オフ時間。 1日の分数。

Y-タイマーセット/リセットボタンが押された場合は1

ttttttttttt-現在の時刻。

ssssssss-パッケージのチェックサム。



シグナルXおよびY-タイマーを設定/リセットするときのみ1に設定されます。 SETまたはCANCELが直接押されたとき。 NおよびFと混同しないでください!

NおよびF-タイマーがオン/オフであることのみを報告しますが、nnnnnnnnnnnまたはfffffffffffは現時点では「不明」(0x600)になる可能性があります。 たとえば、温度上昇ボタンを押すと、タイマーが現在オンの場合、N / F値は1になり、nnnnnnnnnnn / fffffffffffにはオンになっているタイマーの特定の時間が含まれます(オフタイマーの場合は0x600が含まれます)。 エアコンは、対応するX / Yビットが1の場合にのみ、N / Fステータスを変更します。

オンタイマーが設定されていない場合、オンタイムd。 1536 = 0x600 = 0b11000000000。 オフタイマーも同様です。 少なくとも、それはネイティブのリモートが送信するものです。



ビットのストリームをバイトに分割し、ビットを展開します。

 00000010 02
 00100000 20
 1,1100,000 E0
 00000100 04
 00000000 00
 0mmm1FNPモード<< 4 + 8 + FlagOFF << 2 + FlagON << 1 +電源
 00ccccc0温度<< 1
 10,000,000 80
 FFFFvvvvファン<< 4 + Vert
 0000hhhhホリズ
 nnnnnnnn OnTime&0xFF
 ffffXnnn OnTime >> 8 + OffTime&0x0F + ChangeOn << 3
 Yfffffff OffTime >> 4 + ChangeOff << 7
 00010000 10
 00000000 00
 00000001 01
 tttttttt時間と0xFF
 00000ttt時間>> 8
 ssssssss Sum


合計チーム19バイト。



コントローラー



テストのために、ブレッドボード上に回路( ここに借用)を組み立てて、はんだなしで取り付けます。 構成部品



私の回路と参照による回路の違いは、LEDがPB1に接続され、トランジスタのベースがPB3に接続されていることです。



ポートPD7のボタンを放すと、タイマー1はCTCモードで起動し、信号はPB1 / OC1Aに出力され、タイマー2はPB3 / OC2に出力され、主信号が変調されるキャリア周波数になります。 タイマーはプリセレクター8で動作します。



ファームウェア





AVR Studio 4のソースコード。
#include <avr/io.h> #include <avr/interrupt.h> #define F_CPU 8000000 #define LED_CARIER DDB3 #define LED_SIGNAL DDB1 #define BASE 480 #define PAUSE 10000 #define START_1 BASE*8 #define START_2 BASE*4 #define DELIM 520 #define PULSE1 BASE*3 #define PULSE0 BASE unsigned char state = 0; unsigned char byteIndex = 0; unsigned char frameIndex = 0; unsigned char bit = 0; unsigned char phase = 0; unsigned char packetLen = 0; unsigned char process = 0; char header[] = {0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06}; char cmd_ion[] = {0x02, 0x20, 0xE0, 0x04, 0x80, 0x48, 0x33, 0x01}; char cmd_oxygen[] = {0x02, 0x20, 0xE0, 0x04, 0x80, 0x50, 0x33, 0x09}; char cmd_quiet[] = {0x02, 0x20, 0xE0, 0x04, 0x80, 0x81, 0x33, 0x3A}; char* data; char* cmd; unsigned char cmdLen; void stop(); ISR(SIG_OUTPUT_COMPARE1A) { switch (state) { case 0: OCR1AH = START_2 / 256; OCR1AL = START_2 % 256; state = 1; break; case 1: OCR1AH = DELIM / 256; OCR1AL = DELIM % 256; state = 2; byteIndex = 0; frameIndex++; if (frameIndex == 1) { data = header; packetLen = 8; } else { data = cmd; packetLen = cmdLen; } bit = 0; phase = 0; break; case 2: if (byteIndex < packetLen) { if (phase == 0) { if (data[byteIndex]&(1 << bit)) { OCR1AH = PULSE1 / 256; OCR1AL = PULSE1 % 256; } else { OCR1AH = PULSE0 / 256; OCR1AL = PULSE0 % 256; } } else { OCR1AH = DELIM / 256; OCR1AL = DELIM % 256; bit++; if (bit == 8) { bit = 0; byteIndex++; } } phase = 1 - phase; } else { OCR1AH = PAUSE / 256; OCR1AL = PAUSE % 256; if (frameIndex == 2) { stop(); } else { state = 3; } } break; case 3: OCR1AH = START_1 / 256; OCR1AL = START_1 % 256; state = 0; break; } } void start() { state = 0; byteIndex = 0; frameIndex = 0; packetLen = sizeof (header); TCNT1H = 0; TCNT1L = 0; OCR1AH = START_1 / 256; OCR1AL = START_1 % 256; TCCR1A = (1 << COM1A0); TCCR1B = (1 << WGM12) | (1 << CS11); TCNT2 = 0; OCR2 = 13; TCCR2 = (1 << WGM21) | (1 << COM20) | (1 << CS21); TIMSK = (1 << OCIE1A); sei(); } void stop() { cli(); TCCR2 = (1 << WGM21) | (1 << COM20); TCCR1A = (1 << FOC1A); TCCR1B = (1 << WGM12) | (0 << CS12) | (0 << CS11) | (0 << CS10); TIMSK = 0; PORTB = (1 << LED_SIGNAL) | (1 << LED_CARIER); process = 0; } int main(void) { process = 0; PORTB = (1 << LED_SIGNAL) | (1 << LED_CARIER); DDRB = (1 << LED_SIGNAL) | (1 << LED_CARIER); PORTD = (1 << 7); // PD7 input, pull up DDRD = 0; while (1) { int but = (PIND & (1 << PD7)); if (process == 0 && but == 0) { process = 1; } else if (process == 1 && but != 0) { process = 2; cmd = cmd_oxygen; cmdLen = 8; start(); } } }
      
      









おわりに



現在のテストの実装では、ヘッダーと固定コマンドの送信方法がまだわかっています。 しかし、ここで質問がありました-このコントローラーにはどのような実装の深さが必要ですか? 結局、コントローラーに「23度冷却をオンにする」と言うことも、単に「コマンドを送信する」と言って、既に生成されたコマンドでビットストリーム全体を転送することもできます。 ただし、タイミングを指定することもできます。 その後、1つのコントローラーエミッターを介してさまざまなデバイスを制御できます。 コメントであなたが私が決断を下すのを助けることを望みます。

温度センサーのペアを接続して、室温とエアコンからの空気の流れを制御することも計画されています。 これは、フィードバック(たとえば、現在の気候パラメーターを使用したSMS通知)および制御(エアコンがオンになっていますか?)に便利です。



UPD

この記事は、RF24Networkを介したModbusの記事OpenHABのWireless Home Residential Controllerに続きます。



All Articles