iRobot Roomba i7+ Configuration using Rest980

@LUNZ I assume your running the php-nginx container.

If you try hit the image.php file in a browser - you get nothing showing up?

I’ve also noticed that with the webhippie php container you need to add a floor.png file in the vacuum directory otherwise the php file won’t render correctly. Can you check if you have added one of these? Set it to the same dimensions as the map

EDIT: I have updated the ha-rest980-roomba repo to include an example floor.png file in the vacuum directly to ensure the map generates during initial deployment.

Let me know how you go!

When I try to update the docker image in Hassio I get an error.

20-01-26 18:02:59 INFO (SyncWorker_9) [hassio.docker.addon] Start Docker add-on koalazak/rest980 with version latest

20-01-26 18:03:33 INFO (SyncWorker_3) [hassio.docker.interface] Update image koalazak/rest980:latest to c4fe18d5/amd64-addon-rest980:20191217

20-01-26 18:03:33 INFO (SyncWorker_3) [hassio.docker.interface] Pull image c4fe18d5/amd64-addon-rest980 tag 20191217.

20-01-26 18:03:34 ERROR (SyncWorker_3) [hassio.docker.interface] Can’t install c4fe18d5/amd64-addon-rest980:20191217 -> 404 Client Error: Not Found (“pull access denied for c4fe18d5/amd64-addon-rest980, repository does not exist or may require ‘docker login’”).

I changed rest980 from using a docker hub image to building it locally (for better compatibility)

Can you try removing it, refresh your add ons and then try installing it again?

1 Like

Just thought I’d share my floor plan that I made just by taking a screen shot from the roomba app. Obviously not the best but a very quick easy way to get a floor plan!

I had to tweak the colors to get it to show up better on this floorplan.

3 Likes

For anyone still using the lovelace front end to manage cards, here are the three cards fomr @Syrius 's lovelace example broken out.

Dynamic Buttons (Full Clean/Pause/Resume + Dock/EmptyBin

type: horizontal-stack
cards:
  - type: 'custom:button-card'
    entity: rest_command.vacuum_action
    icon: |
      [[[
        if (states['sensor.vacuum_cycle'].state == "Ready")
          return "mdi:play";
        else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
          return "mdi:play-pause";
        return "mdi:pause"
      ]]]
    layout: icon_name
    lock:
      enabled: |
        [[[
          if (states['sensor.vacuum_phase'].state == "Emptying Robot")
            return true;
          return false;
        ]]]
      exemptions: []
    name: |
      [[[
        if (states['sensor.vacuum_cycle'].state == "Ready")
          return "Full Clean";
        else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
          return "Resume";
        return "Pause"
      ]]]
    styles:
      card:
        - height: 50px
    tap_action:
      action: call-service
      service: rest_command.vacuum_action
      service_data:
        command: |
          [[[
            if (states['sensor.vacuum_cycle'].state == "Ready")
              return "start";
            else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
              return "resume";
            return "pause"
          ]]]
    hold_action:
      action: call-service
      service: rest_command.vacuum_action
      service_data:
        command: |
          [[[
            if (states['sensor.vacuum_cycle'].state == "Ready")
              return "start";
            else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
              return "stop";
            return "stop"
          ]]]   
  - type: 'custom:button-card'
    entity: rest_command.vacuum_action
    icon: 'mdi:home-minus'
    layout: icon_name
    lock:
      enabled: |
        [[[
          if (states['sensor.vacuum_phase'].state == "Emptying Robot")
            return true;
          return false;
        ]]]
      exemptions: []
    name: |
      [[[
        if ((states['sensor.vacuum_phase'].state == "Charging") || (states['sensor.vacuum_phase'].state == "Fully Charged") || (states['sensor.vacuum_phase'].state == "Emptying Robot"))
          return "Empty Bin";
        return "Dock"
      ]]]
    styles:
      card:
        - height: 50px
    tap_action:
      action: call-service
      service: rest_command.vacuum_action
      service_data:
        command: dock

Map

aspect_ratio: 0%
type: picture-glance
camera_image: camera.roomba
entities: []

States & Select Room Cleaning

type: entities
entities:
  - entity: sensor.vacuum_phase
  - entity: sensor.vacuum_cycle
  - entity: sensor.vacuum_battery
  - entity: sensor.vacuum_bin
  - entity: sensor.vacuum_dock
  - entity: sensor.vacuum_location
  - entities:
      - input_boolean.vacuum_bathroom
      - input_boolean.vacuum_breakfast_nook
      - input_boolean.vacuum_dining_room
      - input_boolean.vacuum_entryway
      - input_boolean.vacuum_foyer
      - input_boolean.vacuum_great_room
      - input_boolean.vacuum_hallway
      - input_boolean.vacuum_kitchen
      - input_boolean.vacuum_laundry_room
      - input_boolean.vacuum_living_room
      - input_boolean.vacuum_office
      - input_boolean.vacuum_playroom
      - entity: automation.vacuum_clean_rooms
        lock:
          enabled: |
            [[[
              if (states['group.vacuum_rooms'].state == "off")
                return true;
              return false;
            ]]]
          exemptions: []
        name: Clean Rooms
        styles:
          card:
            - height: 50px
        tap_action:
          action: call-service
          service: automation.trigger
          service_data:
            entity_id: automation.vacuum_clean_rooms
        type: 'custom:button-card'
    head:
      label: Selective Room Cleaning
      type: section
    type: 'custom:fold-entity-row'
show_header_toggle: false

I cleaned up the lovelace card to make it a little more compact if anyone is interested.

vacuum

cards:
  - entity: sensor.vacuum_phase
    secondary_info: last-changed
    type: 'custom:multiple-entity-row'
    name: Gerbert
    name_state: Status
    primary:
      entity: sensor.vacuum_battery
      name: Battery
    secondary:
      entity: sensor.vacuum_cycle
      name: Cycle
  - entities:
      - input_boolean.vacuum_dining_room
      - input_boolean.vacuum_kitchen
      - input_boolean.vacuum_hallway
      - input_boolean.vacuum_living_room
      - input_boolean.vacuum_bathroom
      - input_boolean.vacuum_kais_bedroom
      - input_boolean.vacuum_ensuite
      - input_boolean.vacuum_master_bedroom
      - entity: automation.vacuum_clean_rooms
        lock:
          enabled: |-
            [[[
              if (states['group.vacuum_rooms'].state == "off")
                return true;
              return false;
            ]]]
          exemptions: []
        name: Clean Rooms
        styles:
          card:
            - height: 50px
              border-radius: 10px
        tap_action:
          action: call-service
          service: automation.trigger
          service_data:
            entity_id: automation.vacuum_clean_rooms
        type: 'custom:button-card'
    head:
      label: Select Rooms to Clean
      type: section
    type: 'custom:fold-entity-row'
  - type: horizontal-stack
    cards:
      - type: 'custom:button-card'
        color_type: blank-card
        styles:
          card:
            - width: 25px
      - type: 'custom:button-card'
        entity: rest_command.vacuum_action
        icon: |
          [[[
            if (states['sensor.vacuum_cycle'].state == "Ready")
              return "mdi:play";
            else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
              return "mdi:play-pause";
            return "mdi:pause"
          ]]]
        color: 'rgb(68, 115, 158)'
        layout: icon_name
        lock:
          enabled: |
            [[[
              if (states['sensor.vacuum_phase'].state == "Emptying Robot")
                return true;
              return false;
            ]]]
          exemptions: []
        name: |
          [[[
            if (states['sensor.vacuum_cycle'].state == "Ready")
              return "Full Clean";
            else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
              return "Resume";
            return "Pause"
          ]]]
        styles:
          card:
            - border-radius: 10px
        tap_action:
          action: call-service
          service: rest_command.vacuum_action
          service_data:
            command: |
              [[[
                if (states['sensor.vacuum_cycle'].state == "Ready")
                  return "start";
                else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
                  return "resume";
                return "pause"
              ]]]
        hold_action:
          action: call-service
          service: rest_command.vacuum_action
          service_data:
            command: |
              [[[
                if (states['sensor.vacuum_cycle'].state == "Ready")
                  return "start";
                else if ((states['sensor.vacuum_phase'].state == "Stopped/Paused") || (states['sensor.vacuum_phase'].state == "Stuck") || (states['sensor.vacuum_phase'].state == "Charging"))
                  return "stop";
                return "stop"
              ]]]   
      - type: 'custom:button-card'
        entity: rest_command.vacuum_action
        icon: 'mdi:home-minus'
        color: 'rgb(68, 115, 158)'
        layout: icon_name
        lock:
          enabled: |
            [[[
              if (states['sensor.vacuum_phase'].state == "Emptying Robot")
                return true;
              return false;
            ]]]
          exemptions: []
        name: |
          [[[
            if ((states['sensor.vacuum_phase'].state == "Charging") || (states['sensor.vacuum_phase'].state == "Fully Charged") || (states['sensor.vacuum_phase'].state == "Emptying Robot"))
              return "Empty Bin";
            return "Dock"
          ]]]
        styles:
          card:
            - border-radius: 10px
        tap_action:
          action: call-service
          service: rest_command.vacuum_action
          service_data:
            command: dock
      - type: 'custom:button-card'
        color_type: blank-card
        styles:
          card:
            - width: 25px
show_header_toggle: false
title: Vacuum
type: vertical-stack
2 Likes

Nice work @drjared88 !

I didn’t know about about the multiple-entity-row plugin - but that definitely looks clean! :smiley:

Time for some customizing :wink:

I have my first vacuum job going right now since I wiped the setup and reinstalled.

How long should it take for an image to populate for the camera.roomba entity?

Mine still looks like:

image

@chansearrington - the map should update in realtime during the clean.

What do you get when you hit the url directly?

http://<ip/host of docker host>:<nginxphpport>/image.php

a bunch of weird code.

@chansearrington You need to adjust this variable

$vacuum_log = 'https://<ip or fqdn of docker host>:<nginxphpport>/vacuum.log';

with the proper ip/fqdn and port of where the nginx container is located

1 Like

In looking at the image.php file it looks like I need to edit this section:

// ADJUST THESE PARAMETERS
$vacuum_log = 'https://<ip or fqdn of docker host>:<nginxphpport>/vacuum.log';
$overlay_image = 'floor.png';
$show_stuck_positions = true;
$map_width = 1050;
$map_height = 900;
$x_offset = 220;
$y_offset = 220;
$flip_vertical = false;
$flip_horizontal = false;
$ha_rest980 = 'https://<ip or fqdn of home assistant>:<haport>/api/states/sensor.rest980';
$ha_token = '<ha_long_live_token>';
$ha_timezone = 'Australia/Brisbane'; # Supported Timezones https://www.php.net/manual/en/timezones.php
/////////////////

I’m assuming I need to edit the whole section nad add things like a HA_token?

I didn’t notice this part in the setup docs

@chansearrington

Yes you will - and you are correct, I didnt properly call this out in the docs - will amend now.

1 Like

Sweet!! looks like I’m in business!

Thanks for the quick response and help!

No worries - glad its working :smiley:

README has been updated to include this step - thanks for pointing it out @chansearrington !

1 Like

@chansearrington Make sure you update both image.php and image_dev.php

the dev version refreshes each time (without creating the seperate png files or loading the latest.png when its created) - helpful when you have done a full clean for working out the map size, offsets, flips and the overlay floor.png file :+1:

Great work!
Any chance this will do the job for older roombas (i.e. 980)?

The Rest980 part would work but most of the automations and map stuff that @Syrius did woulnd’t work as the 980 as far as I recall does not have persistant maps or room based cleaning. I’m not really sure if there is much benefit running this over the native roomba integration if you don’t have a room based cleaning model.

As @drjared88 said, some of it will be relevant for the 980 model. I know the selective room cleaning definatley wont work, but I think the mapping should actually work (as the code this uses was written for the 980 model :wink: )

I suggest you give it a shot and see?

some of the commands might need to be modified - refer here for specifics