diff --git a/ESPHomeRoombaComponent.h b/ESPHomeRoombaComponent.h index 1f3926a..aa79848 100644 --- a/ESPHomeRoombaComponent.h +++ b/ESPHomeRoombaComponent.h @@ -4,42 +4,52 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public PollingComponent { public: - //Sensor *distanceSensor; + // Sensor *distanceSensor; Sensor *voltageSensor; Sensor *currentSensor; Sensor *batteryChargeSensor; Sensor *batteryCapacitySensor; Sensor *batteryPercentSensor; + Sensor *batteryTemperatureSensor; TextSensor *chargingSensor; TextSensor *activitySensor; + Sensor *driveSpeedSensor; + TextSensor *oiModeSensor; - static RoombaComponent* instance(uint8_t brcPin, UARTComponent *parent, uint32_t updateInterval) { - static RoombaComponent* INSTANCE = new RoombaComponent(brcPin, parent, updateInterval); + static RoombaComponent* instance(uint8_t brcPin, UARTComponent *parent, uint32_t updateInterval, bool lazy650Enabled) { + static RoombaComponent* INSTANCE = new RoombaComponent(brcPin, parent, updateInterval, lazy650Enabled); return INSTANCE; } void setup() override { - // High-impedence on the BRC_PIN - // see https://github.com/johnboiles/esp-roomba-mqtt/commit/fa9af14376f740f366a9ecf4cb59dec2419deeb0#diff-34d21af3c614ea3cee120df276c9c4ae95053830d7f1d3deaf009a4625409ad2R140 - pinMode(this->brcPin, INPUT); + if (this->lazy650Enabled) { + // High-impedence on the BRC_PIN + // see https://github.com/johnboiles/esp-roomba-mqtt/commit/fa9af14376f740f366a9ecf4cb59dec2419deeb0#diff-34d21af3c614ea3cee120df276c9c4ae95053830d7f1d3deaf009a4625409ad2R140 + pinMode(this->brcPin, INPUT); + } else { + pinMode(this->brcPin, OUTPUT); + digitalWrite(this->brcPin, HIGH); + } register_service(&RoombaComponent::on_command, "command", {"command"}); } void update() override { - long now = millis(); - // Wakeup the roomba at fixed intervals - if (now - lastWakeupTime > 50000) { - ESP_LOGD("custom", "Time to wakeup"); - lastWakeupTime = now; - if (!wasCleaning) { - if (wasDocked) { - wake_on_dock(); + if (this->lazy650Enabled) { + long now = millis(); + // Wakeup the roomba at fixed intervals + if (now - lastWakeupTime > 50000) { + ESP_LOGD("custom", "Time to wakeup"); + lastWakeupTime = now; + if (!wasCleaning) { + if (wasDocked) { + wake_on_dock(); + } else { + brc_wakeup(); + } } else { brc_wakeup(); } - } else { - brc_wakeup(); } } @@ -48,6 +58,7 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin int16_t current; uint16_t batteryCharge; uint16_t batteryCapacity; + int16_t batteryTemperature; flush(); @@ -56,9 +67,13 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin SensorVoltage, SensorCurrent, SensorBatteryCharge, - SensorBatteryCapacity + SensorBatteryCapacity, + SensorBatteryTemperature, + SensorDistance, + SensorOIMode }; - uint8_t values[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; + + uint8_t values[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; bool success = getSensorsList(sensors, sizeof(sensors), values, sizeof(values)); if (!success) { @@ -71,8 +86,10 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin current = values[3] * 256 + values[4]; batteryCharge = values[5] * 256 + values[6]; batteryCapacity = values[7] * 256 + values[8]; - - std::string activity = this->get_activity(charging, current); + batteryTemperature = values[9]; + std::string oiMode = get_oimode(values[10]); + + std::string activity = get_activity(charging, current); wasCleaning = activity == "Cleaning"; wasDocked = activity == "Docked"; @@ -101,6 +118,10 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin this->batteryPercentSensor->publish_state(battery_level); } + if (this->batteryTemperatureSensor->state != batteryTemperature) { + this->batteryTemperatureSensor->publish_state(batteryTemperature); + } + if (this->chargingState != charging) { this->chargingState = charging; this->chargingSensor->publish_state(ToString(charging)); @@ -109,6 +130,14 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin if (activity.compare(this->activitySensor->state) != 0) { this->activitySensor->publish_state(activity); } + + if (this->driveSpeedSensor->state != this->speed) { + this->driveSpeedSensor->publish_state(this->speed); + } + + if (oiMode.compare(this->oiModeSensor->state) != 0) { + this->oiModeSensor->publish_state(oiMode); + } } private: @@ -117,17 +146,25 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin int lastWakeupTime = 0; bool wasCleaning = false; bool wasDocked = false; - - RoombaComponent(uint8_t brcPin, UARTComponent *parent, uint32_t updateInterval) : UARTDevice(parent), PollingComponent(updateInterval) { + int16_t speed = 0; + + bool lazy650Enabled = false; + + RoombaComponent(uint8_t brcPin, UARTComponent *parent, uint32_t updateInterval, bool lazy650Enabled) : UARTDevice(parent), PollingComponent(updateInterval) { this->brcPin = brcPin; + this->lazy650Enabled = lazy650Enabled; this->voltageSensor = new Sensor(); this->currentSensor = new Sensor(); this->batteryChargeSensor = new Sensor(); this->batteryCapacitySensor = new Sensor(); this->batteryPercentSensor = new Sensor(); + this->batteryTemperatureSensor = new Sensor(); this->chargingSensor = new TextSensor(); this->activitySensor = new TextSensor(); + + this->driveSpeedSensor = new Sensor(); + this->oiModeSensor = new TextSensor(); } typedef enum { @@ -186,13 +223,20 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin } ChargeState; void brc_wakeup() { - ESP_LOGD("custom", "brc_wakeup"); - pinMode(this->brcPin, OUTPUT); - digitalWrite(this->brcPin, LOW); - delay(200); - pinMode(this->brcPin, OUTPUT); - delay(200); - start_oi(); // Start + if (this->lazy650Enabled) { + ESP_LOGD("custom", "brc_wakeup"); + pinMode(this->brcPin, OUTPUT); + digitalWrite(this->brcPin, LOW); + delay(200); + pinMode(this->brcPin, OUTPUT); + delay(200); + start_oi(); // Start + } else { + digitalWrite(this->brcPin, LOW); + delay(1000); + digitalWrite(this->brcPin, HIGH); + delay(100); + } } void on_command(std::string command) { @@ -209,16 +253,39 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin spot(); } else if (command == "wakeup") { - this->brc_wakeup(); + brc_wakeup(); } else if (command == "wake_om_dock") { - this->wake_on_dock(); + wake_on_dock(); } else if (command == "sleep") { sleep(); - } else { - ESP_LOGD("custom", "unknown command " + command); } + else if (command == "go_max") { + ESP_LOGI("roomba", "go max"); + alter_speed(1000); + } else if (command == "go_faster") { + ESP_LOGI("roomba", "go faster"); + alter_speed(100); + } else if (command == "go_slower") { + ESP_LOGI("roomba", "slow it down"); + alter_speed(-100); + } else if (command == "go_right") { + ESP_LOGI("roomba", "easy right"); + drive(speed, -250); + } else if (command == "go_left") { + ESP_LOGI("roomba", "easy left"); + drive(this->speed, 250); + } else if (command == "halt") { + ESP_LOGI("roomba", "HALT"); + this->speed = 0; + drive(0,0); + } else if (command == "drive") { + ESP_LOGI("roomba", "DRIVE mode"); + this->speed = 0; + safeMode(); + } +ESP_LOGI("roomba", "ACK %s", command.c_str()); } void start_oi() { @@ -241,6 +308,41 @@ class RoombaComponent : public UARTDevice, public CustomAPIDevice, public Pollin write(143); // Dock } + void alter_speed(int16_t step) { + int16_t speed = this->speed + step; + + if (speed > 500) + speed = 500; + else if (speed < -500) + speed = -500; + + this->speed = speed; + this->driveSpeedSensor->publish_state(speed); + this->drive(this->speed, 0); + } + + void drive(int16_t velocity, int16_t radius) { + write(137); + write((velocity & 0xff00) >> 8); + write(velocity & 0xff); + write((radius & 0xff00) >> 8); + write(radius & 0xff); + } + + void safeMode() { + write(131); + } + + std::string get_oimode(uint8_t mode) { + switch(mode) { + case 0: return "off"; + case 1: return "passive"; + case 2: return "safe"; + case 3: return "full"; + default: return "unknown"; + } + } + void cover() { write(135); } diff --git a/example/roomba.yaml b/example/roomba.yaml index 15d694c..5d79299 100644 --- a/example/roomba.yaml +++ b/example/roomba.yaml @@ -7,13 +7,13 @@ esphome: substitutions: name: "roomba" - # BRC pin, uart_bus, polling interval in milliseconds - init: 'RoombaComponent::instance(D5, id(uart_bus), 10000);' + # BRC pin, uart_bus, polling interval in milliseconds, enable hack for lazy 650 wakeup + init: 'RoombaComponent::instance(D5, id(uart_bus), 10000, true);' uart: id: uart_bus - tx_pin: D1 - rx_pin: D2 + tx_pin: TX + rx_pin: RX baud_rate: 115200 # Enable logging @@ -52,7 +52,7 @@ sensor: - platform: custom lambda: |- auto r = ${init} - return {r->voltageSensor, r->currentSensor, r->batteryChargeSensor, r->batteryCapacitySensor, r->batteryPercentSensor}; + return {r->voltageSensor, r->currentSensor, r->batteryChargeSensor, r->batteryCapacitySensor, r->batteryPercentSensor, r->batteryTemperatureSensor, r->driveSpeedSensor}; sensors: - name: "${name} voltage" unit_of_measurement: "V" @@ -69,12 +69,23 @@ sensor: - name: "${name} battery" unit_of_measurement: "%" accuracy_decimals: 0 + - name: "${name} temp" + unit_of_measurement: "°C" + accuracy_decimals: 0 + - name: "${name} drive speed" + unit_of_measurement: "mm/s" + accuracy_decimals: 0 text_sensor: - platform: custom lambda: |- auto r = ${init} - return {r-> chargingSensor, r->activitySensor}; + return {r->chargingSensor, r->activitySensor, r->oiModeSensor}; text_sensors: - name: "${name} charging state" - - name: "${name} activity" \ No newline at end of file + - name: "${name} activity" + - name: "${name} OI mode" + +switch: + - platform: safe_mode + name: "Vacuum Restart (Safe Mode)"