devices.esphome.io

4moms Mamaroo 4

4moms Mamaroo 4

Device Type: misc
Electrical Standard: global
Board: esp32

4moms Mamaroo 4

Product description

We bought a 4moms Mamaroo 4 multi-motion baby swing for our baby and I realized it has built-in bluetooth module. Witch made me thinking if I can reverse-engineer original app to control swing using BLE client. Luckily there already was a project that helped me a bit. I used some tools (apktool and jadx) to decompile android apk file and understand how it works.

Finally I was able to made this config witch lets you fully control your swing using external ESP32 module. Also it should be possible to put it inside the swing and connect to power jack using step-down module.

Config

substitutions:
name: 4moms-mamaroo-4
friendly_name: 4moms Mamaroo 4
device_description: Multi-motion baby swing
service_uuid: 622d0100-2416-0fa7-e132-2f1495cc2ce0
characteristic_uuid: 622d0101-2416-0fa7-e132-2f1495cc2ce0
mac_address: 00:00:00:00:00:00
esphome:
name: ${name}
friendly_name: ${friendly_name}
comment: ${device_description}
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
web_server:
ota:
platform: esphome
logger:
level: WARN
api:
esp32_ble_tracker:
on_ble_advertise:
then:
- lambda: |-
if (x.get_name().rfind("Blimp", 0) == 0) {
ESP_LOGI("ble_adv", "New 4moms Mamaroo 4 found");
ESP_LOGI("ble_adv", " Name: %s", x.get_name().c_str());
ESP_LOGI("ble_adv", " MAC address: %s", x.address_str().c_str());
ESP_LOGD("ble_adv", " Advertised service UUIDs:");
for (auto uuid : x.get_service_uuids()) {
ESP_LOGD("ble_adv", " - %s", uuid.to_string().c_str());
}
}
ble_client:
- mac_address: ${mac_address}
id: mamaroo
on_connect:
- ble_client.ble_write:
id: mamaroo
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: !lambda return {0x43, 0x09};
script:
- id: write_parameter
mode: restart
parameters:
address: byte
value: byte
then:
- logger.log:
format: "Sending parameter to address: %d with value: %d..."
args: ['address', 'value']
level: VERBOSE
- ble_client.ble_write:
id: mamaroo
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
value: !lambda return {0x43, address, value};
- id: set_power
parameters:
value: bool
then:
- script.execute:
id: write_parameter
address: 0x01
value: !lambda 'return value ? 1 : 0;'
- id: set_is_moving
parameters:
value: bool
then:
- script.execute:
id: write_parameter
address: 0x02
value: !lambda 'return value ? 1 : 0;'
- id: set_is_playing
parameters:
value: bool
then:
- script.execute:
id: write_parameter
address: 0x03
value: !lambda 'return value ? 1 : 0;'
- id: set_motion
parameters:
value: int
then:
- script.execute:
id: write_parameter
address: 0x04
value: !lambda 'return std::min(std::max(1, value), 5);'
- id: set_sound
parameters:
value: int
then:
- script.execute:
id: write_parameter
address: 0x05
value: !lambda 'return std::min(std::max(0, value), 5);'
- id: set_speed
parameters:
value: int
then:
- script.execute:
id: write_parameter
address: 0x06
value: !lambda 'return std::min(std::max(0, value), 5);'
- id: set_volume
parameters:
value: int
then:
- script.execute:
id: write_parameter
address: 0x07
value: !lambda 'return std::min(std::max(0, value), 5);'
sensor:
- platform: uptime
type: seconds
name: Uptime
- platform: ble_client
id: data
ble_client_id: mamaroo
type: characteristic
service_uuid: ${service_uuid}
characteristic_uuid: ${characteristic_uuid}
# notify: true # Notifications are triggered to often and floods MCU
update_interval: 1000ms
lambda: |-
for (uint8_t i = 0; i < x.size(); i++) {
ESP_LOGV("4moms", "Byte %d: 0x%02X", i, x[i]);
}
if (x.size() >= 10) {
if (x[0] == 0x53) {
id(power).publish_state(x[5] == 1);
id(is_moving).publish_state(x[6] == 1);
id(is_playing).publish_state(x[7] == 1);
if (id(power).state) {
id(motion).publish_state(id(motion).at(x[1] - 1).value());
id(speed).publish_state(x[2]);
if (x[3] > 0) id(sound).publish_state(id(sound).at(std::min((int) x[3], 5) - 1).value());
id(volume).publish_state(x[4]);
}
}
}
return {};
binary_sensor:
- platform: template
id: is_moving
name: Motion
device_class: moving
- platform: template
id: is_playing
name: Sound
device_class: sound
switch:
- platform: template
id: power
name: Power
optimistic: true
restore_mode: DISABLED
turn_on_action:
- script.execute:
id: set_power
value: true
- script.execute:
id: set_motion
value: !lambda |-
auto index = id(motion).active_index();
return index.has_value() ? index.value() + 1 : 1;
- script.execute:
id: set_speed
value: !lambda 'return id(speed).state;'
- script.execute:
id: set_is_moving
value: !lambda 'return id(speed).state > 0;'
- script.execute:
id: set_sound
value: !lambda |-
auto index = id(sound).active_index();
return index.has_value() ? index.value() + 1 : 1;
- script.execute:
id: set_volume
value: !lambda 'return id(volume).state;'
- script.execute:
id: set_is_playing
value: !lambda 'return id(volume).state > 0;'
turn_off_action:
- script.execute:
id: set_power
value: false
select:
- platform: template
id: motion
name: Motion
optimistic: true
options:
- Car Ride
- Kangaroo
- Tree Swing
- Rock-A-Bye
- Wave
icon: mdi:swap-vertical-variant
set_action:
- script.execute:
id: set_motion
value: !lambda 'return id(motion).index_of(x).value() + 1;'
- script.execute:
id: set_is_moving
value: true
- platform: template
id: sound
name: Sound
optimistic: true
options:
- Rain
- White Noise
- Sea ​​Surf
- Heart Beat
- AUX
icon: mdi:music-note-sixteenth
set_action:
- script.execute:
id: set_sound
value: !lambda 'return id(sound).index_of(x).value() + 1;'
- script.execute:
id: set_is_playing
value: true
number:
- platform: template
id: speed
name: Speed
optimistic: true
min_value: 0
max_value: 5
step: 1
icon: mdi:speedometer
set_action:
- script.execute:
id: set_speed
value: !lambda 'return x;'
- script.execute:
id: set_is_moving
value: !lambda 'return x > 0;'
- platform: template
id: volume
name: Volume
optimistic: true
min_value: 0
max_value: 5
step: 1
icon: mdi:volume-high
set_action:
- script.execute:
id: set_volume
value: !lambda 'return x;'
- script.execute:
id: set_is_playing
value: !lambda 'return x > 0;'
Edit this page on GitHub