ARCHIVED FORUM -- March 2012 to February 2022READ ONLY FORUM
This is the second Archived Forum which was active between 1st March 2012 and 23rd February 2022
I successfully integrated a little arduino micro board in the Beolink case, i use it to decode some IR code from the BEO4 to turn on or off my lights, keeping the rest of the commands compatible with my Beosound 3200.
Is someone is interested to know 'how to', just drop me a message...
Hi,
this sounds very interesting to me. What type of Arduino board did you use? Is the source code available?
Ralph-Marcus
hello,
this is quit simple for the moment, simply wiring the ir eye pin 7 to the arduino (for test i use an arduino mega 2560, and use the bromate library to decode ir signal.
Next step now, i will disconnect b&o processor from the board, and connect completely the arduino in place, i already know how to handle the i2c lines related to the audio processor and the ir eye I/O.
I keep you informed as soon as i have time to sketch some diagrams and show some code. My arduino is linked to and RGB Led driver module so i control the lights with my beo4 remote control
read beomote library, not bromate...
ok, i have some code to share, but is it possible to share that on this forum ? how can i do that ?
Seems to be a very nice project. What kind of lights do you control and how?
in fact, this is the part of the project that is already working, i have an arduino mega 2560, connected to a little rgb led driver board, a ethernet card, a temperature/pressure jauge and and IR moment detector. This is the basis setup for a home automation system with sound control, light control, temperature/pressure and presence control. This is already working by the remote control of a beo4 remote control. I don't see where i can dowload the code on the forum, so i will send it like messages, you will have to regale the code to have it complete...
PART1: Main code
#include <Beomote.h>
#include <Ethernet.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include "RGBdriver.h"
//Clocked In RGB LED Strip interface --
#define LED_CLK 24 //Led strip driver
#define LED_DIO 26 //Led strip driver
//Beoremote IR Code table -------------
#include "BeoRemote_Lookup_Table.h"
//Declare the RGB LED Driver
RGBdriver LEDDriver(LED_CLK,LED_DIO);
// assign a MAC address for the Ethernet controller.---
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// assign an IP address for the controller: ---
IPAddress ip(192, 168, 123, 101);
// Initialize the Ethernet server library
// with the IP address and port
// (port 80 is default for HTTP):
EthernetServer server(80);
Adafruit_BMP280 bmp; //BMP280 I2C connection
//For I2C Temperature sensor, I2C line are pin 20:SDA and pin 21:SCL
//pin definition
static const int IRBOPin = 22; //IR Detector Bang&Olufsen
//static const int IRSTDPin = 4;
static const int audioPin = 28; //Relay command output for audio power on/off
static const int blowerPin = 30; //Relay command output for blower power on/off
static const int PIRPin = 6; //PIR movment detector pin
//status
boolean audioStatus = false;
boolean blowerStatus = false;
int currentLedStripColor = 0;
boolean lightChannelSelect = false;
int PIRCalibrationTime = 30; //time needed for PIR to calibrate and stabilize
//the time when the PIR sensor outputs a low impulse
long unsigned int lowIn;
//the amount of milliseconds the PIR sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;
boolean lockLow = true;
boolean takeLowTime;
boolean BTGO = false; //This is used to toggle a wait for next key for selection of relay to toggle
boolean DOOR = false; //This is used on remote to wait for a four digit code to toggle alarm ON/OFF
String ALARMCODE = ""; //This variable is used to hold the code ticked in by remotecontrol
static const int RELAY_ON = 0;
static const int RELAY_OFF = 1;
static const int ON = 1;
static const int OFF = 0;
static const int YellowColor = 1;
static const int RedColor = 2;
static const int BlueColor = 3;
static const int GreenColor = 4;
static const int WhiteColor = 5;
float temperature = 0;
float humidity = 0;
float pressure = 0;
String URLCommandString = String(100); //string for fetching data from address //fetch the header part of the URL
String WorkMode; //Isolate the GET command to see if we are in ALARM mode
boolean getAlarm = false; //false: normal mode true: alarm mode activated
boolean intrusionDetection = false; //false:no intrusion detected, true: intrusion detected transmitted to central unit
boolean setAlarm = false; //if set to true, command is send to Central Unit to switch house in alarm mode
void setup() {
pinMode(IRBOPin,INPUT);
pinMode(PIRPin,INPUT);
// pinMode(IRSTDPin,INPUT);
pinMode(audioPin,OUTPUT);
pinMode(blowerPin,OUTPUT);
getAlarm = false;
setAlarm = false;
intrusionDetection = false;
BTGO=false;
DOOR=false;
LEDDriver.begin();
LEDDriver.SetColor(0,0,0);
LEDDriver.end();
//at power up, audio relay and blower relay are also shutdown
digitalWrite(audioPin,RELAY_OFF);
digitalWrite(blowerPin,RELAY_OFF);
Serial.begin(9600);
lightChannelSelect = false;
currentLedStripColor = 0;
Serial.println(F("BMP280 test"));
if (!bmp.begin()) {
Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
while (1);
}
//Initialize B&O IR eye
Beo.initialize(IRBOPin);
//Start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
// give the IR sensor and Ethernet shield time to set up:
//delay(1000);
//give all the interfaces some time to calibrate
Serial.print("calibrating sensor & ethernet ");
for(int i = 0; i < PIRCalibrationTime; i++){
Serial.print(".");
delay(300);
Serial.println(" done");
Serial.println("SENSOR & ETHERNET ACTIVE");
delay(50);
void loop() {
checkIREye();
//checkBMP280(); //only for serial monitoring purpose...
checkEthernet();
checkPIRSensor();
void checkPIRSensor() {
if (getAlarm == true) {
if(digitalRead(PIRPin) == HIGH){
if(lockLow){
//makes sure we wait for a transition to LOW before any further output is made:
lockLow = false;
intrusionDetection = true;
takeLowTime = true;
if(digitalRead(PIRPin) == LOW){
if(takeLowTime){
lowIn = millis(); //save the time of the transition from high to LOW
takeLowTime = false; //make sure this is only done at the start of a LOW phase
//if the sensor is low for more than the given pause,
//we assume that no more motion is going to happen
if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
void checkBMP280() {
Serial.print(F("Temperature = "));
Serial.print(bmp.readTemperature()-5);
Serial.println(" *C");
Serial.print(F("Pressure = "));
Serial.print(bmp.readPressure()/100);
Serial.println(" hPa");
Serial.print(F("Approx altitude = "));
Serial.print(bmp.readAltitude(1021.60)); // this should be adjusted to your local forcase
Serial.println(" m");
Serial.println();
//delay(2000);
void checkIREye() {
BeoCommand cmd;
if (Beo.receive(cmd)) {
//Serial.print(cmd.link, HEX);
//Serial.print(":");
//Serial.print(cmd.address, HEX);
//Serial.print("!");
//Serial.println(cmd.command, HEX);
checkRemoteCmd(cmd);
void checkEthernet() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
//read char by char HTTP request
if (URLCommandString.length() < 100) {
//store characters to string
URLCommandString = URLCommandString += c;
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// output the value of each analog input pin
client.print("temperature ");
client.print(bmp.readTemperature()-5);
client.print("</br>");
client.print("pression ");
client.print(bmp.readPressure()/100);
client.print("CURRENT UNIT ALARM MODE: ");
client.print("ACTIVE");
} else {
client.print("INACTIVE");
client.print("CURRENT HOUSE ALARM MODE: ");
if (setAlarm == true) {
client.print("INTRUSION DETECTION: ");
if (intrusionDetection == true) {
client.print("INTRUSION DETECTED!");
client.print("NO INTRUSION...");
client.println("</html>");
break;
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
} else if (c != '\r') {
// you've gotten a character on the current line
//Serial.write(c);
currentLineIsBlank = false;
// give the web browser time to receive the data
delay(1);
//Check if we are in ALARM mode...
WorkMode = URLCommandString.substring(3,10);
if(WorkMode.indexOf("/alarm") > 0) {
getAlarm = true;
//Check if we are in ALARM RESET mode...
if(WorkMode.indexOf("/reset") > 0) {
// close the connection:
client.stop();
Serial.println("client disconnected");
URLCommandString="";
void toggleLedStripColor(int color) {
if (currentLedStripColor == color) {
setLedStripColor(OFF);
currentLedStripColor = color;
setLedStripColor(color);
void setLedStripColor(int color) {
switch(color) {
case OFF: LEDDriver.begin();
case WhiteColor: LEDDriver.begin();
LEDDriver.SetColor(255,255,255);
case YellowColor: LEDDriver.begin();
LEDDriver.SetColor(255,100,20);
case RedColor: LEDDriver.begin();
LEDDriver.SetColor(255,0,0);
case GreenColor: LEDDriver.begin();
LEDDriver.SetColor(0,255,0);
case BlueColor: LEDDriver.begin();
LEDDriver.SetColor(0,0,255);
default: LEDDriver.begin();
void composeCode(String code) {
ALARMCODE = ALARMCODE + code;
if (ALARMCODE.length() == 4) {
if (ALARMCODE == "3521") {
setAlarm = !setAlarm;
if(setAlarm == true) {
setLedStripColor(RedColor);
setLedStripColor(GreenColor);
setLedStripColor(currentLedStripColor);
ALARMCODE="";
void checkRemoteCmd(BeoCommand cmd ) {
switch (cmd.command) {
case SPEC_RED: Serial.print("Red LED");
if (lightChannelSelect) {
toggleLedStripColor(RedColor);
case SPEC_GREEN: Serial.print("Green LED");
toggleLedStripColor(GreenColor);
case SPEC_BLUE: Serial.print("Blue LED");
toggleLedStripColor(BlueColor);
case SPEC_YELLOW: Serial.print("Orange LED");
toggleLedStripColor(YellowColor);
case BEO1_PAD_GO: Serial.print("Pad GO");
BTGO = true;
case BEO4_PAD_GO: Serial.print("Pad GO");
case NUM_0: Serial.print("0");
if (BTGO) {
audioStatus=false;
blowerStatus=false;
if(DOOR) {
composeCode("0");
case NUM_1: Serial.print("1");
if(audioStatus) {
}else {
digitalWrite(audioPin,RELAY_ON);
audioStatus=true;
composeCode("1");
case NUM_2: Serial.print("2");
if(blowerStatus) {
digitalWrite(blowerPin,RELAY_ON);
blowerStatus=true;
composeCode("2");
case NUM_3: if(DOOR) {
composeCode("3");
case NUM_4: if(DOOR) {
composeCode("4");
case NUM_5: if(DOOR) {
composeCode("5");
case NUM_6: if(DOOR) {
composeCode("6");
case NUM_7: if(DOOR) {
composeCode("7");
case NUM_8: if(DOOR) {
composeCode("8");
case NUM_9: if(DOOR) {
composeCode("9");
case CMD_LIGHT: Serial.print("LIGHTCHANNELSELECT TOGGLE:");
lightChannelSelect = true;
if (currentLedStripColor == 0) {
setLedStripColor(WhiteColor);
currentLedStripColor = WhiteColor;
toggleLedStripColor(currentLedStripColor);
case ACT_MENU: DOOR=!DOOR; //just toggle the DOOR boolean on /off
Serial.print("DOOR: " + DOOR);
case CMD_TV: lightChannelSelect = false;
case CMD_RADIO: lightChannelSelect = false;
case CMD_CD: lightChannelSelect = false;
case CMD_DVD: lightChannelSelect = false;
case CMD_SAT: lightChannelSelect = false;
case CMD_VTAPE: lightChannelSelect = false;
case CMD_MYVIDEO: lightChannelSelect = false;
case CMD_MYPC: lightChannelSelect = false;
case CMD_MYMUSIC: lightChannelSelect = false;
case CMD_TEXT: lightChannelSelect = false;
case CMD_AUX: lightChannelSelect = false;
case CMD_NETRADIO: lightChannelSelect = false;
case CMD_NMUSIC: lightChannelSelect = false;
case CMD_CINEMA: lightChannelSelect = false;
PART 2: Beoremote_Lookup_Table
//Bang&Olufsen Remote code table
//This table cross reference codes from the BEO4 and BEORemote One
//controllers, some codes are used differently in the two command sets,
//those differences are highlighted in the naming when needed (BEO4...,BEO1...)
//Command Set summary
//-------------------------------------------------------------------
static const int NUM_0 = 0x0;
static const int NUM_1 = 0x1;
static const int NUM_2 = 0x2;
static const int NUM_3 = 0x3;
static const int NUM_4 = 0x4;
static const int NUM_5 = 0x5;
static const int NUM_6 = 0x6;
static const int NUM_7 = 0x7;
static const int NUM_8 = 0x8;
static const int NUM_9 = 0x9;
static const int CMD_TV = 0x80;
static const int CMD_RADIO = 0x81;
static const int CMD_CD = 0x92;
static const int CMD_DVD = 0x86;
static const int CMD_LIGHT = 0x9B;
static const int CMD_SAT = 0x8A;
static const int CMD_VTAPE = 0x85;
static const int CMD_MYVIDEO = 0x87;
static const int CMD_MYPC = 0x8B;
static const int CMD_MYMUSIC = 0x91;
static const int CMD_TEXT = 0x88;
static const int CMD_GUIDE = 0x40;
static const int CMD_DTV = 0x8A;
static const int CMD_AUX = 0x83;
static const int CMD_NETRADIO = 0x93;
static const int CMD_NMUSIC = 0x94;
static const int CMD_CINEMA = 0x58;
static const int ACT_RECORD = 0x37;
static const int ACT_MENU = 0x5C;
static const int ACT_DOOR = 0xA8;
static const int ACT_STOP = 0x36;
static const int ACT_MUTE = 0x0D;
static const int ACT_SHUTDOWN = 0x0C;
static const int ACT_EXIT = 0x7F;
static const int ACT_VOL_UP = 0x60;
static const int ACT_VOL_DWN = 0x64;
static const int ACT_REWIND = 0x32;
static const int ACT_FORWARD = 0x34;
static const int ACT_PAUSE = 0x36;
static const int ACT_BACK = 0x14;
static const int ACT_INFO = 0x43;
static const int ACT_LIST = 0x58;
static const int BEO4_PAD_UP = 0x1E;
static const int BEO4_PAD_DWN = 0x1F;
static const int BEO4_PAD_LEFT = 0x32;
static const int BEO4_PAD_RIGHT = 0x34;
static const int BEO4_PAD_GO = 0x35;
static const int BEO1_PAD_UP = 0xCA;
static const int BEO1_PAD_DWN = 0xCB;
static const int BEO1_PAD_LEFT = 0xCC;
static const int BEO1_PAD_RIGHT = 0xCD;
static const int BEO1_PAD_GO = 0x13;
static const int BEO1_ACT_PGMUP = 0x1E;
static const int BEO1_ACT_PGMDWN = 0x1F;
static const int SPEC_GREEN = 0xD5;
static const int SPEC_YELLOW = 0xD4;
static const int SPEC_RED = 0xD9;
static const int SPEC_BLUE = 0xD8;
static const int ADD_BEOSOUND=0xA5;
static const int ADD_BEOSOUND2=0xAD;
static const int ADD_BEOSOUND3=0xB5;
static const int ADD_BEOSOUND4=0xBD;
static const int ADD_BEOSOUND5=0x25;
static const int ADD_BEOSOUND6=0x2D;
static const int ADD_BEOSOUND7=0x35;
static const int ADD_BEOSOUND8=0x3D;
static const int ADD_BEO4AUDIO=0x01;
static const int ADD_BEOVISION=0xA0;
Now the next step will be to interface with the SDA/SCL signals coming from the IR EYE (Pin 1 and 4) to be able to control also the lights, but maybe to also use the remaining IO ports of the PCF8574 (there are four unused ports apparently, that i could use to commend relays or leds...)
After that, following step will be to interface with the TDA 7315 sound processor with is also I2C device
Then the hard work will begin... the idea is to compare (with the arduino serial port as debugger), the code generated be the BEO4, and a same command coming from a Masterlink or Powerlink data, trying to isolate the codes and build a correct structure for generating those code. I will also refer to the MGLW protocol guide...
Idea is then to remove the processor board from B&O and replace it completely by an Arduino board...
I'm impressed! Who doesn't want to control his B&O home with a B&O remote... :-)
OK, i have put a little video on youtube to show the actual results...
you can check it on: https://www.youtube.com/watch?v=crnG4kiArQU
Bien fait Alain!
I am doing similar integration, but since I never liked any remote controls I am focusing more on voice commands and automated integration with iOS HomeKit.
I am currently reverse-engineering ML, listening to the telegram and interpreting it isn't difficult, however pretending that you are a legitimate ML node or moreover lock master is still to be worked out. If you manage to solve/re-work lock managment protocol faster than I do, fine bottle of champainge from Épernay is on me;)
Yeah!, do you work on the iOS side only or do you also use some arduino or other stuff (raspberry pi, ?), i am currently working on the blink active setup, but once finished, i will send you what i will discover about the protocol... Keep the good work on!
I use RPi and ESP8266
I have a huge problem getting my Beolab5 speakers to turn on when they receive a Trigger signal from my non-B&O receiver. Someone told me its because it needs a 'data' signal as well - which the BEO4 transmits.
Would it be possible to record this 'data-snippet' with Arduino and then somehow get it to retransmit this data-snippet when I need to send it?
Did you figure out the i2c communication from the eye?
Yes, this is very simple as it is based on a simple 8574 chipset. By the way, if is is for interest for some people, I recently hacked a BEOSOUND5 that was stuck, replaced the mainboard by an Arduino, and managed to decode all the wheel information (volume, selector, etc...)
I only have a problem with the IR detector with does not work well with the beomote library (for the moment)
I will couple the Arduino to a raspberry pi to have a multimedia unit .
Would you mind sharing it?
BL8000, BL8002, BL4000, BL3, BL12.2, BS5, BS7000, BS9000, BS9500, BS2000, Ouverture