Scannen und Senden von Infrarot-Fernbedienungssignalen mit GPIO von Raspberry Pi Ich habe diesen Artikel das letzte Mal geschrieben. Die Fernbedienung für Fernseher und Deckenleuchten ist einfach und einfach, da immer das gleiche Signal ausgegeben wird, wenn Sie dieselbe Taste drücken. Die Fernbedienung für Klimaanlagen ist jedoch etwas Besonderes und nicht so. Bei einer Klimaanlage kennt die Fernbedienung den aktuellen Zustand der Klimaanlage, und die Bedienung beim Drücken der Taste ändert sich je nach Zustand. Wenn Sie jedoch beim Ausschalten der Klimaanlage in Form eines Signals scannen, beim Ausschalten bei 28 Grad ein Signal und beim Einschalten der Heizung bei 20 Grad ein Signal, können Sie das Kühlen und Heizen ein- und ausschalten. Wird sein. Da es sich jedoch um eine große Sache handelt, möchte ich die Fernbedienung analysieren, damit die eingestellte Temperatur und Windrichtung frei eingestellt werden können.
Wir werden den Scan verwenden und Programme aus dem vorherigen Artikel senden. Wenn Sie ihn also nicht gelesen haben, lesen Sie ihn bitte zuerst.
Dies ist die für die Analyse verwendete Fernbedienung. Der Modellname lautet NH122 205AL Der Typ, der eine Klimaanlage in Kirigamine hat.
Zunächst werde ich die Fernbedienung der Klimaanlage scannen.
pi@raspberrypi:~/IR $ ./scan 20 > heat20
GPIO Pin Number : 20
Scanning begin
Scanning end
Output begin
Output end
pi@raspberrypi:~/IR $ cat heat20
3499 1681
460 1257
462 1256
460 396
463 396
462 400
461 1255
461 399
459 400
461 1256
461 1256
460 400
(Weggelassen)
459 1260
459 400
458 400
458 13283
3470 1680
461 1256
461 1258
460 399
460 399
461 399
459 1256
461 399
460 399
459 1259
460 1255
461 400
(Weggelassen)
458 1264
457 399
459 399
458
Sehen Sie sich dies an, um festzustellen, welches Format verwendet wird. Erstens, da es nicht von SONY hergestellt wird, ist es entweder NEC oder Ie Seikyo. Kommunikationsformat der Infrarot-Fernbedienung Wenn Sie es mit der Website hier vergleichen, Die Beleuchtungszeit 3499 der ersten Zeile, dh der Leiter, beträgt ungefähr das Achtfache der Beleuchtungszeit 460, wenn die Daten der zweiten und der nachfolgenden Zeilen gesendet werden, sodass Sie sehen können, dass es sich um ein selbst erstelltes kooperatives Format handelt. Es gibt auch einen Ort, an dem die Beleuchtungszeit bis zu 3470 beträgt, sodass diese Fernbedienung möglicherweise ein 2-Frame-Signal sendet. Aber es scheint sich nicht zu wiederholen. Ich kann es jedoch überhaupt nicht verstehen, selbst wenn ich mir so viel anschaue. Schreiben wir also ein Programm, das dies in hexadezimal konvertiert.
Konvertieren Sie zunächst die gescannte Datei in hexadezimal. Im hausgemachten kooperativen Format wird der Leiter nach dem Senden in 8-Bit-Reihenfolge vom LSB des ersten Bytes an das MSB gesendet. Danach werden das 2. und 3. Byte der Reihe nach angezeigt, und der Frame endet, wenn das Licht für die letzten 8 ms oder länger ausgeschaltet wird.
Ignorieren Sie vorerst Trailer und Repeat und konzentrieren Sie sich nur auf Leader und Data. Das Format der Fernbedienung hat eine Modulationseinheit T, und die gesendeten Informationen werden durch die Beleuchtungszeit und die Löschzeit bestimmt, die mehrmals T beträgt. Leader hat eine Beleuchtungszeit von 8T und eine Beleuchtungszeit von 4T. Wenn 0 übertragen wird, ist die Beleuchtungszeit T und die Beleuchtungszeit T. Wenn 1 gesendet wird, beträgt die Beleuchtungszeit T und die Beleuchtungszeit 3T. Wird sein. Basierend auf der Tatsache, dass T 350 bis 500 beträgt, wird bei langer Beleuchtungszeit von Leader bestimmt, ob die Beleuchtungszeit und die Löschzeit ungefähr gleich 0 sind, und wenn die Löschzeit länger als die Beleuchtungszeit ist, wird dies durch den rauen Zustand bestimmt. Machen.
aeha.c
//
// aeha.c
// Copyright © 2018 Hiroki Kawakami. All rights reserved.
//
#include<stdio.h>
#include<stdlib.h>
int main() {
int count, offset = -1;
unsigned int on, off;
unsigned char byte = 0;
while(1) {
count = scanf("%u%u", &on, &off);
if (count < 2 || off == 0) {
break;
}
if (on > 1500) {
if (offset >= 0) printf("\n");
offset = 0;
byte = 0;
} else {
byte |= (off > on * 2) << offset++;
if ((offset & 7) == 0) {
printf("%02X ", byte);
offset = 0;
byte = 0;
}
}
}
printf("\n");
return 0;
}
$ gcc -o aeha aeha.c
Konvertieren Sie die beim Scannen erstellte heat20-Datei
pi@raspberrypi:~/IR $ cat heat20 | ./aeha
23 CB 26 01 00 20 48 04 30 6A 00 00 00 00 10 00 00 2B
23 CB 26 01 00 20 48 04 30 6A 00 00 00 00 10 00 00 2B
Jetzt können Sie das von der Fernbedienung gesendete Signal hexadezimal sehen. Sie können sehen, dass diese Fernbedienung zweimal denselben Frame sendet.
Da ich das Signal hexadezimal sehen konnte, scanne ich das Signal der Fernbedienung in verschiedenen Modi und vergleiche es, um es zu analysieren. Ich scanne es jedoch nacheinander und konvertiere es in hexadezimal. Es ist mühsam zu vergleichen. Aber es ist okay. Es ist nicht nur zum Spaß, dass ich Standard-E / A für Datei-E / A verwendet habe. Auf diese Weise können Sie das Scanprogramm und das hexadezimale Konvertierungsprogramm direkt mit einer Pipe verbinden.
$ while true; do ./scan 20 2>/dev/null | ./aeha; done
./scan 20 | ./Ich kann das Scan-Programm und das hexadezimale Konvertierungsprogramm mit aeha mit einer Pipe verbinden, aber die stderr-Ausgabe des Scan-Programms ist ein Hindernis, also 2>/dev/Ich werfe es als null weg. Und allein damit endet das Programm nach einmaligem Scannen. Während dies zutrifft, wird das Programm in einer Endlosschleife neu gestartet.
Auf diese Weise können Sie das Fernbedienungssignal kontinuierlich scannen und als Hexadezimalwert anzeigen.
Wenn Sie fertig sind, drücken Sie Strg + C, um den Vorgang zu beenden.
### Lauf
Sie müssen lediglich den oben beschriebenen Befehl ausführen, nacheinander Fernbedienungssignale an den Sensor senden und die angezeigten Werte vergleichen.
pi@raspberrypi:~/IR $ while true; do ./scan 20 2>/dev/null | ./aeha; done 23 CB 26 01 00 20 48 04 30 40 00 00 00 00 10 00 00 01 23 CB 26 01 00 20 48 04 30 40 00 00 00 00 10 00 00 01 23 CB 26 01 00 20 48 03 30 40 00 00 00 00 10 00 00 00 23 CB 26 01 00 20 48 03 30 40 00 00 00 00 10 00 00 00 23 CB 26 01 00 20 48 02 30 40 00 00 00 00 10 00 00 23 CB 26 01 00 20 48 02 30 40 00 00 00 00 10 00 00 FF 23 CB 26 01 00 20 48 01 30 40 00 00 00 00 10 00 00 FE 23 CB 26 01 00 20 48 01 30 40 00 00 00 00 10 00 00 FE 23 CB 26 01 00 20 48 00 30 80 00 00 00 00 10 00 00 3D 23 CB 26 01 00 20 48 00 30 80 00 00 00 00 10 00 00 3D
In seltenen Fällen wird es möglicherweise nicht normal konvertiert, aber da diese Fernbedienung zweimal dasselbe Signal sendet, gibt es kein Problem bei der Analyse.
Dies ist das Ergebnis des Drückens der Taste, um die eingestellte Temperatur in Richtung des Sensors zu senken und fünf Signale von der Erwärmung um 20 Grad auf die Erwärmung um 16 Grad der Reihe nach einzugeben.
Ich denke, dass das letzte 1 Byte zur Fehlererkennung verwendet wird. Ignorieren Sie es also und Sie können sehen, dass sich der Wert des 7. Bytes (das 0. Byte ganz links) geändert hat.
pi@raspberrypi:~/IR $ while true; do ./scan 20 2>/dev/null | ./aeha; done 23 CB 26 01 00 20 58 0C 36 40 00 00 00 00 10 00 00 1F 23 CB 26 01 00 20 58 0C 36 40 00 00 00 00 10 00 00 1F 23 CB 26 01 00 20 58 0D 36 40 00 00 00 00 10 00 00 20 23 CB 26 01 00 20 58 0D 36 40 00 00 00 00 10 00 00 20 23 CB 26 01 00 20 58 0E 36 40 00 00 00 00 10 00 00 21 23 CB 26 01 00 20 58 0E 36 40 00 00 00 00 10 00 00 21 23 CB 26 01 00 20 58 0F 36 80 00 00 00 00 10 00 00 62 23 CB 26 01 00 20 58 0F 36 80 00 00 00 00 10 00 00 62
Darüber hinaus ist dies das Ergebnis des Drückens der Taste, um die eingestellte Temperatur von 28 Grad auf 31 Grad zu erhöhen und vier Signale der Reihe nach einzugeben, und es ist ersichtlich, dass sich auch der Wert des 7. Bytes ändert.
Wenn Sie den Wert des 7. Bytes berechnen, können Sie sehen, dass er von der eingestellten Temperatur -16 ist.
Daher wurde festgestellt, dass die eingestellte Temperatur im 7. Byte gespeichert ist.
Fügen Sie danach auf die gleiche Weise für den Betriebsmodus, die Windgeschwindigkeit, die Windrichtung usw. einfach Signale hinzu, die nur eine Bedingung in der angegebenen Reihenfolge ändern, und sehen Sie die Wertänderung.
### Letzte 1 Byte
Auf dem Referenzstandort wurde die Fernbedienung der Klimaanlage von National analysiert. Die Fernbedienung hatte das hausgemachte kooperative Format, und das letzte 1 Byte waren die unteren 8 Bits der Summe aller Bytes. Als ich es mit der Fernbedienung überprüfte, die ich gerade analysiere, wurden die unteren 8 Bits wie auf der Referenzstelle hinzugefügt.
## Analyseergebnis
![解析.png](https://qiita-image-store.s3.amazonaws.com/0/242402/8227486d-9575-6147-3c5d-33c8e94b4954.png)
Das Signal beim Einstellen des Timers wird nicht analysiert. Es ist einfacher und flexibler, es programmgesteuert zu steuern.
Wenn der Windbereich 0 ist, wird der für den linken und rechten Wind angegebene Wert verwendet. Wenn hier angegeben, ist die Ausrichtung die im Windbereich angegebene, ohne die linken und rechten Windwerte zu verwenden.
# Senden
Nachdem die Analyse abgeschlossen ist, müssen Sie nur noch ein Programm schreiben, das Signale gemäß den Analyseergebnissen generiert. Das Programm, das das Signal generiert, wurde mit Node.js erstellt, damit es später problemlos über das Web bedient werden kann.
## Programm
#### **`mbac.js`**
```js
//
// mbac.js
// Copyright © 2018 Hiroki Kawakami. All rights reserved.
//
var bytes = [0x23, 0xcb, 0x26, 0x01, 0x00, 0x00, 0x58, 12, 0x32, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0];
var aeha = function(T, bytes, repeats, interval) {
var result = "";
var i = 0;
var length = bytes.length;
while (true) {
result += T * 8 + " " + T * 4 + "\n"; // Leader
for (var j = 0; j < length; j++) {
for (var k = 0; k < 8; k++) {
if ((bytes[j] & (1 << k)) != 0) { // 1
result += T + " " + T * 3 + "\n";
} else { // 0
result += T + " " + T + "\n";
}
}
}
if (++i >= repeats) {
result += T;
break;
} else {
result += T + " " + interval + "\n"; // Trailer
}
}
return result;
}
var UpdateCheckByte = function() {
var sum = 0;
for (var i = 0; i < bytes.length - 1; i++) {
sum += bytes[i];
}
bytes[bytes.length - 1] = sum & 0xff;
}
var SetPower = function(power) {
if (power.toLowerCase !== undefined) {
power = power.toLowerCase()
}
if (!power || power == "off" || power == "false") {
bytes[5] = 0x00;
savedState.power = false;
} else {
bytes[5] = 0x20;
savedState.power = true;
}
}
var SetMode = function(mode) { //Modus einstellen (cool:Klimaanlage, heat:Heizung, dry:Entfeuchtung, wind:Gebläse)
mode = mode.toLowerCase();
var byte = {"cool": 0x58, "heat": 0x48, "dry": 0x50, "wind": 0x38}[mode];
if (byte === undefined) {
console.log("Mode %s is not defined!", mode);
return false;
}
SetPower(true);
bytes[6] = byte;
savedState.mode = mode;
if (mode == "cool") {
SetTemperature(savedState.coolTemperature);
bytes[8] = (bytes[8] & 0xf0) | 0x6;
} else if (mode == "heat") {
SetTemperature(savedState.heatTemperature);
} else if (mode == "dry") {
SetDryIntensity(savedState.dryIntensity);
}
return true;
}
var SetTemperature = function(temperature) { //Stellen Sie die eingestellte Temperatur ein (16~31)
if (temperature < 16 || temperature > 31) {
console.log("Temperature %d is out of range (16 ~ 31).", temperature);
return false;
}
bytes[7] = temperature - 16;
if (savedState.mode == "cool") {
savedState.coolTemperature = temperature;
} else if (savedState.mode == "heat") {
savedState.heatTemperature = temperature;
}
return true;
}
var SetDryIntensity = function(intensity) { //Entfeuchtungsstärke (hoch:Stärke, normal:Standard, low:schwach)
intensity = intensity.toLowerCase();
var byte = {"high": 0x0, "normal": 0x2, "low": 0x4}[intensity];
if (byte === undefined) {
console.log("Dry intensity %s is not defined!", intensity);
return false;
}
bytes[8] = (bytes[8] & 0xf0) | byte;
savedState.dryIntensity = intensity;
return true;
}
var SetWindHorizontal = function(horizontal) { //Windrichtung links und rechts (1:ganz links~ 3:Zentral~ 5:Ganz rechts, 6:Drehung)
if (horizontal <= 0 || horizontal > 6) {
console.log("Horizontal wind direction %d is out of range (1 ~ 6).", horizontal);
return false;
}
if (horizontal == 6) {
horizontal = 0xc;
}
bytes[8] = (bytes[8] & 0xf) | (horizontal << 4);
savedState.horizontal = horizontal;
return true;
}
var SetWindVertical = function(vertical) { //Bei Windverbesserung (0:Automatisch, 1:oben~ 5:Unterseite, 6:Drehung)
if (vertical < 0 || vertical > 6) {
console.log("Vertical wind direction %d is out of range (0 ~ 6).", vertical);
return false;
}
if (vertical == 6) {
vertical = 7;
}
bytes[9] = (bytes[8] & 0b11000111) | (vertical << 3);
savedState.vertical = vertical;
return true;
}
var SetWindSpeed = function(speed) { //Windgeschwindigkeit (0:Automatisch, 1:schwach, 2:Während ~, 3:Stärke, 4:mächtig)
if (speed < 0 || speed > 4) {
console.log("Wind speed %d is out of range (0 ~ 4).", speed);
return false;
}
var powerful = 0x00;
if (speed == 4) {
speed = 3;
powerful = 0x10;
}
bytes[9] = (bytes[9] & 0b11111000) | speed;
bytes[15] = powerful;
savedState.speed = speed;
return true;
}
var SetWindArea = function(area) { //Windbereich (keiner:Verwenden Sie die linken und rechten Windwerte, whole:Das ganze, left:Linke Hälfte, right:Rechte Hälfte)
var byte = {"none": 0x00, "whole": 0x8, "left": 0x40, "right": 0xc0}[area.toLowerCase()];
if (byte === undefined) {
console.log("Wind area %s is not defined!", area);
return false;
}
bytes[13] = byte;
savedState.area = area;
return true;
}
var fs = require("fs");
var savedState = {
"power": false,
"mode": "cool",
"coolTemperature": 28,
"heatTemperature": 20,
"dryIntensity": "normal",
"horizontal": 5,
"vertical": 0,
"speed": 0,
"area": "none"
};
try {
savedState = JSON.parse(fs.readFileSync("mbac.sav", "utf8"));
} catch(error) {}
try {
if (savedState.mode !== undefined) {
SetMode(savedState.mode);
}
if (savedState.power !== undefined) {
SetPower(savedState.power);
}
if (savedState.horizontal !== undefined) {
SetWindHorizontal(savedState.horizontal);
}
if (savedState.vertical !== undefined) {
SetWindVertical(savedState.vertical);
}
if (savedState.speed !== undefined) {
SetWindSpeed(savedState.speed);
}
if (savedState.area !== undefined) {
SetWindArea(savedState.area);
}
} catch(error) {console.error(error)}
var SaveState = function() {
fs.writeFile('mbac.sav', JSON.stringify(savedState));
}
if (require.main === module) {
var i = 2;
while (i < process.argv.length) {
var key = process.argv[i];
if (key == "-p" || key == "--power") {
SetPower(process.argv[i + 1]);
i += 2;
} else if (key == "-m" || key == "--mode") {
if (!SetMode(process.argv[i + 1])) {
console.log("Invalid value of mode option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-t" || key == "--temperature") {
if (!SetTemperature(process.argv[i + 1])) {
console.log("Invalid value of temperature option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-d" || key == "--dry_intensity") {
if (!SetDryIntensity(process.argv[i + 1])) {
console.log("Invalid value of dry intensity option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-h" || key == "--horizontal") {
if (!SetWindHorizontal(process.argv[i + 1])) {
console.log("Invalid value of wind horizontal option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-v" || key == "--vertical") {
if (!SetWindVertical(process.argv[i + 1])) {
console.log("Invalid value of wind vertical option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-s" || key == "--speed") {
if (!SetWindSpeed(process.argv[i + 1])) {
console.log("Invalid value of wind speed option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else if (key == "-a" || key == "--area") {
if (!SetWindArea(process.argv[i + 1])) {
console.log("Invalid value of wind area option \"%s\"", process.argv[i + 1]);
return;
}
i += 2;
} else {
console.log("Invalid option key \"%s\"", key);
return;
}
}
UpdateCheckByte();
SaveState();
var signal = aeha(430, bytes, 2, 13300);
console.log(signal);
}
Erstens ist Bytes ein Array, das die erzeugten Signale speichert.
Die aeha-Funktion ist eine Funktion, die die Beleuchtungs- / Löschzeit der LED aus dem Byte-Array gemäß dem selbst erstellten kooperativen Format ausgibt.
Die UpdateCheckByte-Funktion ist eine Funktion, die den Prüfwert am Ende des Signals berechnet und festlegt.
Danach gibt es eine Funktion zum Einstellen verschiedener Zustände der Klimaanlage.
var fs = require("fs");
Von nun an wird es ein Programm sein, das den vorherigen Zustand der Klimaanlage wiederherstellt und den aktuellen Zustand speichert. Auf diese Weise können Sie nur das Teil angeben, das Sie ändern möchten, ohne jedes Mal alle Zustände der Klimaanlage anzugeben.
if (require.main === module)Der Inhalt wertet Befehlszeilenargumente aus und führt sie aus. Derzeit beabsichtige ich nicht, die Operation regelmäßig über die Befehlszeile zu verwenden, daher ist die Implementierung hier angemessen.
## Lauf
[Scannen und Senden von Infrarot-Fernbedienungssignalen mit GPIO von Raspberry Pi](https://qiita.com/Hiroki_Kawakami/items/3f7d332797d188dc9022)
Das Sendeprogramm verwendet das im obigen Artikel beschriebene. Bitte beachten Sie dies für die spezifische Verwendung.
Kühlung 30 Grad
#### **`node mbac.js -m cool -t 30 | sudo ./send 18`**
Heizung 20 Grad
node mbac.js -m heat -t 20 | sudo ./send 18
Ausschalten
#### **`node mbac.js -p off | sudo ./send 18`**
Sie können auch mit den folgenden Optionen arbeiten
Das Programm selbst ist einfach, aber ich habe es nicht getestet, so dass es möglicherweise fehlerhaft ist.
Analysieren Sie das Fernbedienungssignal mit Rasberry Pi 3 (Aktualisierung der Ergebnisse der 10/1-Fernsteuerungssignalanalyse) Kommunikationsformat der Infrarot-Fernbedienung
Recommended Posts