This is my approach to mimic non connected controller behavior, while connected to BT. Train will react to action bricks as well as pushes and stops.
I use the vision sensor in “COLOR” mode which returns one of the predefined colors. “RGB” mode may drain battery faster due to more frequent changes and more frequent BLE transmission.
Speed sensor returns the raw value converted to integer, but I haven’t yet implement ed any interpolation to make sure it is somewhere between -100 and 100.
Now at least we can redefine or even extend behavior for action bricks. The good thing that the sensor in “COLOR” mode supports more colors than the 5 original action bricks.
Enjoy.
substitutions:
service_uuid: '00001623-1212-efde-1623-785feabcd123'
characteristic_uuid: '00001624-1212-efde-1623-785feabcd123'
esphome:
name: duplo-steam-train
friendly_name: Duplo Steam Train
includes:
- duplo.h
esp32:
board: esp32dev
framework:
type: arduino
logger:
api:
encryption:
key: !secret enc_key
ota:
password: !secret ota_pwd
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
globals:
- id: motor_on
type: bool
restore_value: no
initial_value: 'false'
- id: white_on
type: bool
restore_value: no
initial_value: 'false'
esp32_ble_tracker:
ble_client:
- mac_address: "6C:B2:FD:83:AA:31"
id: train_hub
on_connect:
then:
- lambda: |-
ESP_LOGD("train", "Connected to Train");
- delay: 1s
# activate vision sensor in COLOR mode
- script.execute:
id: activate_single
port: !lambda "return VISION_SENSOR_PORT_ID;"
mode: !lambda "return VISION_SENSOR_MODE_COLOR;"
# activate speed sensor in SPEED mode
- script.execute:
id: activate_single
port: !lambda "return SPEED_SENSOR_PORT_ID;"
mode: !lambda "return SPEED_SENSOR_MODE_SPEED;"
on_disconnect:
then:
- lambda: |-
ESP_LOGD("train", "Disconnected from Train");
sensor:
- platform: ble_client
type: characteristic
id: ble_sensor
ble_client_id: train_hub
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
lambda: |-
ESP_LOGD("train", "Sensor raw bytes: [{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d}]", x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12]);
switch(x[3]) {
case VISION_SENSOR_PORT_ID:
{
int color = x[4];
if (x[4] == 1 || x[4] == 5) {
color = color + 1;
}
if (color == 255) {
color = 11;
}
id(hub_color).publish_state((float)color);
break;
}
case SPEED_SENSOR_PORT_ID:
{
int16_t speed = x[4] | (int16_t)(x[5] << 8);
id(hub_speed).publish_state((float)speed);
break;
}
}
return 0;
notify: true
- platform: template
id: hub_color
filters:
- debounce: 0.2s
on_value:
then:
- lambda: |-
int value = (int)x;
id(hub_color_text).publish_state(COLORS[value]);
switch (value) {
case RED:
id(brake).press();
id(stop).press();
break;
case BLUE:
id(brake).press();
id(stop).press();
id(fill_water).press();
delay(4000);
id(speed_2).press();
break;
case YELLOW:
id(horn).press();
break;
case GREEN:
id(brake).press();
if (id(hub_speed).state < 0) {
id(stop).press();
id(speed_2).press();
} else {
id(stop).press();
id(backward).press();
}
break;
case WHITE:
if (id(white_on)) {
id(light_off).press();
id(white_on) = false;
} else {
id(light_white).press();
id(white_on) = true;
}
break;
}
- platform: template
id: hub_speed
name: Speed
on_value:
then:
- lambda: |-
if (!id(motor_on)) {
if (x > 10) {
id(speed_2).press();
id(motor_on) = true;
return;
}
if (x < -10) {
id(backward).press();
id(motor_on) = true;
return;
}
}
if (x == 0.0) {
id(motor_on) = false;
}
text_sensor:
- platform: template
id: hub_color_text
name: Color
switch:
- platform: ble_client
ble_client_id: train_hub
name: Train
script:
# activate updates for given port and given mode
- id: activate_single
parameters:
port: char
mode: char
then:
- ble_client.ble_write:
id: train_hub
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: !lambda |-
std::vector<unsigned char> result { 0x0a, 0x00, 0x41, port, mode, 0x01, 0x00, 0x00, 0x00, 0x01 };
return result;
- id: prepare_ble
then:
- ble_client.ble_write:
id: train_hub
service_uuid: 00001623-1212-efde-1623-785feabcd123
characteristic_uuid: 00001624-1212-efde-1623-785feabcd123
value: [0x0a, 0x00, 0x41, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01]
- id: switch_speed
parameters:
value: char
then:
- script.execute:
id: prepare_ble
- ble_client.ble_write:
id: train_hub
service_uuid: 00001623-1212-efde-1623-785feabcd123
characteristic_uuid: 00001624-1212-efde-1623-785feabcd123
value: !lambda |-
std::vector<unsigned char> v = {0x08, 0x00, 0x81, 0x00, 0x01, 0x51, 0x00};
v.push_back(value);
return v;
- id: make_sound
parameters:
value: char
then:
- script.execute:
id: prepare_ble
- ble_client.ble_write:
id: train_hub
service_uuid: 00001623-1212-efde-1623-785feabcd123
characteristic_uuid: 00001624-1212-efde-1623-785feabcd123
value: !lambda |-
std::vector<unsigned char> v = {0x08, 0x00, 0x81, 0x01, 0x11, 0x51, 0x01};
v.push_back(value);
return v;
- id: lights
parameters:
value: char
then:
- script.execute:
id: prepare_ble
- ble_client.ble_write:
id: train_hub
service_uuid: 00001623-1212-efde-1623-785feabcd123
characteristic_uuid: 00001624-1212-efde-1623-785feabcd123
value: !lambda |-
std::vector<unsigned char> v = {0x08, 0x00, 0x81, 0x11, 0x11, 0x51, 0x00};
v.push_back(value);
return v;
button:
- platform: template
name: "Speed 1"
id: speed_1
icon: mdi:play
on_press:
- script.execute:
id: switch_speed
value: 0x1e
- platform: template
name: "Speed 2"
id: speed_2
icon: mdi:step-forward
on_press:
- script.execute:
id: switch_speed
value: 0x32
- platform: template
name: "Speed 3"
id: speed_3
icon: mdi:step-forward-2
on_press:
- script.execute:
id: switch_speed
value: 0x64
- platform: template
name: "Stop"
id: stop
icon: mdi:stop
on_press:
- script.execute:
id: switch_speed
value: 0x00
- platform: template
name: "Backward"
id: backward
icon: mdi:step-backward
on_press:
- script.execute:
id: switch_speed
value: 0xce
- platform: template
name: "Sound: Brake"
id: brake
icon: mdi:stop
on_press:
- script.execute:
id: make_sound
value: 0x03
- platform: template
name: "Sound: depart"
id: depart
on_press:
- script.execute:
id: make_sound
value: 0x05
- platform: template
name: "Sound: fill water"
id: fill_water
icon: mdi:water
on_press:
- script.execute:
id: make_sound
value: 0x07
- platform: template
name: "Sound: horn"
id: horn
icon: mdi:bugle
on_press:
- script.execute:
id: make_sound
value: 0x09
- platform: template
name: "Sound: steam"
id: steam
icon: mdi:kettle-steam
on_press:
- script.execute:
id: make_sound
value: 0x0A
- name: "Light: Off"
platform: template
on_press:
- script.execute:
id: lights
value: 0x00
- name: "Light: Pink"
platform: template
on_press:
- script.execute:
id: lights
value: 0x01
- name: "Light: Purple"
platform: template
on_press:
- script.execute:
id: lights
value: 0x02
- name: "Light: Blue"
platform: template
on_press:
- script.execute:
id: lights
value: 0x03
- name: "Light: Light Blue"
platform: template
on_press:
- script.execute:
id: lights
value: 0x04
- name: "Light: Cyan"
platform: template
on_press:
- script.execute:
id: lights
value: 0x05
- name: "Light: Green"
platform: template
on_press:
- script.execute:
id: lights
value: 0x06
- name: "Light: Yellow"
platform: template
on_press:
- script.execute:
id: lights
value: 0x07
- name: "Light: Orange"
platform: template
on_press:
- script.execute:
id: lights
value: 0x08
- name: "Light: Red"
platform: template
on_press:
- script.execute:
id: lights
value: 0x09
- name: "Light: White"
platform: template
on_press:
- script.execute:
id: lights
value: 0x0A
duplo.h
static const char VISION_SENSOR_PORT_ID = 0x12;
static const char VISION_SENSOR_MODE_COLOR = 0x00;
static const char VISION_SENSOR_MODE_CTAG = 0x01;
static const char VISION_SENSOR_MODE_REFLECTIVITY = 0x02;
static const char VISION_SENSOR_MODE_RGB = 0x03;
static const int BLACK = 0;
static const int PINK = 1;
static const int PURPLE = 2;
static const int BLUE = 3;
static const int LIGHTBLUE = 4;
static const int CYAN = 5;
static const int GREEN = 6;
static const int YELLOW = 7;
static const int ORANGE = 8;
static const int RED = 9;
static const int WHITE = 10;
static const int NONE = 255;
static const char *COLORS[12] = {"black", "pink", "purple", "blue", "lightblue", "cyan", "green", "yellow", "orange", "red", "white", "none"};
static const char SPEED_SENSOR_PORT_ID = 0x13;
static const char SPEED_SENSOR_MODE_SPEED = 0x00;
static const char SPEED_SENSOR_MODE_COUNT = 0x01;
static const char VOLTAGE_SENSOR_PORT_ID = 0x14;