I have been working on an IR remote control project to assist my elderly father control his cable TV box and TV itself. I have a version working using a B4A kiosk mode app on a tablet connected via Bluetooth to an Arduino UNO which drives two IR emitters; one for the cable TV box and one for the TV.
But this Talk to your CD player using Google Home project piqued my interest and I began duplicating it in B4R.
I've created B4R code which connects the ESP8266 to my network and can drive an IR emitter to control the TV, but I'm struggling to replicate the functionality of the original Arduino code:
particularly where it appears to set the endpoint to "ir-interface" (!MDNS.begin("ir-interface"))
in lieu of the 192.168.0.15 assigned to the ESP8266 and handles calls to the endpoint (Framework::server.on("/ir", handleRoot).
Below is my current code which can extract a code to trigger sending of the respective IR code via a web browser, eg. 192.168.0.15/?req=power:
but I think it's pretty clunky and it works only once, with follow-up calls ignored, because there is an error thrown as reported in the log:
Any pointers or suggestions on how I should use better or other B4R code to achieve the functionality of the original Arduino project code or at least address the error which prevents follow-up calls, would be appreciated.
But this Talk to your CD player using Google Home project piqued my interest and I began duplicating it in B4R.
I've created B4R code which connects the ESP8266 to my network and can drive an IR emitter to control the TV, but I'm struggling to replicate the functionality of the original Arduino code:
B4X:
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <framework.h>
#define PanasonicAddress (0x4004)
typedef struct {
char const * name;
uint32_t code;
} button_t;
button_t buttons[] = {
{ "power", 0x0538BC81 },
{ "pause", 0x05505005 },
{ "play", 0x05505005 },
{ "next song", 0x0538526F },
{ "previous song", 0x053892AF },
{ "track 1", 0x05380835 },
{ "track 2", 0x053888B5 },
{ "track 3", 0x05384875 },
{ "track 4", 0x0538C8F5 },
{ "track 5", 0x05382815 },
{ "track 6", 0x0538A895 },
{ "track 7", 0x05386855 },
{ "track 8", 0x0538E8D5 },
{ "track 9", 0x05381825 },
{ "two digits", 0x0538211C },
{ "volume up", 0x05000401 },
{ "volume down", 0x05008481 },
{ NULL, 0x0 }
};
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
void handleRoot(void)
{
String message = "";
if (Framework::server.args() >= 1 &&
Framework::server.argName(0) == "req") {
String buttonReq = Framework::server.arg(0);
button_t const *p;
for (p = buttons; p->name; p++) {
if ( String(p->name) == buttonReq ) {
break;
}
}
if (p->name) {
message += "Sending ";
message += p->name;
message += "\n\n";
irsend.sendPanasonic(PanasonicAddress, p->code);
} else {
message += "'";
message += buttonReq;
message +="' not found\n\n";
}
}
message += "Valid commands are:<ul>\n\n";
for (button_t const *p = buttons; p->name; p++) {
message += "<li>";
message += "<a href=\"/ir?ir=";
message += p->name;
message += "\">";
message += p->name;
message += "</li>\n";
}
message += "</ul>";
Serial.println(message);
Framework::server.send( 200, "text/html", message );
}
void setup()
{
Framework::begin();
Framework::server.on("/ir", handleRoot);
Framework::server.begin();
delay(500); // Wait a bit for the serial connection to be establised.
irsend.begin();
if (!MDNS.begin("ir-interface")) {
Serial.println("Error setting up MDNS responder!");
while(1) {
delay(1000);
}
}
MDNS.addService("http", "tcp", 80);
Serial.println("Ready");
}
void loop() {
// test only
irsend.sendPanasonic(PanasonicAddress, 0x05505005);
Framework::handle();
}
particularly where it appears to set the endpoint to "ir-interface" (!MDNS.begin("ir-interface"))
in lieu of the 192.168.0.15 assigned to the ESP8266 and handles calls to the endpoint (Framework::server.on("/ir", handleRoot).
Below is my current code which can extract a code to trigger sending of the respective IR code via a web browser, eg. 192.168.0.15/?req=power:
B4X:
Sub Process_Globals
Private wifi As ESP8266WiFi
Private server As WiFiServerSocket
Private sp As Serial
Private astream As AsyncStreams
Private bc As ByteConverter
Private irsend As IrSend
End Sub
Private Sub AppStart
sp.Initialize(115200)
Log("AppStart")
ScanNetworks
ConnectToNetwork
irsend.Enable(4, 38) 'frequency = 38khz
server.Initialize(80, "server_NewConnection")
server.Listen
End Sub
Sub Astream_NewData (Buffer() As Byte)
If bc.IndexOf(Buffer, "GET") <> -1 Then
Dim command As String
Dim i1 As Int = 0
Dim i2 As Int = 0
For Each b1() As Byte In bc.Split(Buffer, " ")
If i1 = 1 Then
For Each b2() As Byte In bc.Split(b1, "=")
If i2 = 1 Then
command = bc.StringFromBytes(b2)
sendNewData(command)
End If
i2 = i2 + 1
Next
End If
i1 = i1 + 1
Next
Else
CallSubPlus("CloseConnection", 200, 0)
End If
End Sub
Private Sub CloseConnection(u As Byte)
Log("close connection")
If server.Socket.Connected Then
server.Socket.Stream.Flush
server.Socket.Close
End If
End Sub
Sub AStream_Error
Log("error")
End Sub
Sub Server_NewConnection (NewSocket As WiFiSocket)
Log("Client connected")
astream.Initialize(NewSocket.Stream, "Astream_NewData", "Astream_Error")
End Sub
Sub sendNewData(command As String)
Select command
Case "power"
irsend.sendPanasonic(0x4004, 0x100BCBD) 'Toggle TV power on/off
Log("Sending IR code for: ", command)
End Select
End Sub
Sub ScanNetworks
Dim numberOfNetworks As Byte = wifi.Scan
Log("Found ", numberOfNetworks, " networks")
For c = 0 To numberOfNetworks - 1
Log("SSID: ", wifi.ScannedSSID(c), "|RSSI: ", wifi.ScannedRSSI(c))
Next
End Sub
Sub ConnectToNetwork
If wifi.Connect2("SSID", "password") = False Then
Log("Error connecting to network")
Return
Else
Log("Connected to network")
Log("My IP address: ", wifi.LocalIp)
End If
End Sub
but I think it's pretty clunky and it works only once, with follow-up calls ignored, because there is an error thrown as reported in the log:
B4X:
Found 5 networks
SSID: Telstra1943|RSSI: -30
SSID: EQ|RSSI: -91
SSID: DIRECT-E6-HP OfficeJet Pro 6970|RSSI: -50
SSID: Fon WiFi|RSSI: -89
SSID: Telstra0C3E|RSSI: -93
Connected to network
My IP address: 192.168.0.15
Client connected
Sending IR code for: power
close connection
error
close connection
close connection
close connection
Any pointers or suggestions on how I should use better or other B4R code to achieve the functionality of the original Arduino project code or at least address the error which prevents follow-up calls, would be appreciated.
Last edited: