Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use StateVacuumEntity instead of VacuumEntity #32

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0848f06
Add by me a coffe badge
deblockt Jun 12, 2020
27fa353
feat: add vacuum error management
deblockt Jun 12, 2020
b434045
feat: Add error code detail for code 3
deblockt Jun 12, 2020
e5a63d8
refactor: use svgwrite insteadof drawSvg
deblockt Jun 17, 2020
cf03e3c
feat: update map size in function of clear area
deblockt Jun 18, 2020
1c9c098
ci(hass): update codeowner
deblockt Jul 6, 2020
293ea96
ci(hass): add info.md
deblockt Jul 6, 2020
a1f749c
ci: update the hacs action
deblockt Jul 28, 2021
ddfa488
feat: use config_flow to add create entity
deblockt Jul 28, 2021
ad59032
doc: update the readme for new configuration flow
deblockt Jul 28, 2021
a2b05d0
ci: upgrade version to 0.0.6
deblockt Jul 28, 2021
64357f9
ci: add hassfest validation
deblockt Jul 28, 2021
b4ba642
feat: add camera entity
deblockt Jul 29, 2021
ea8ca61
ci: upgrade version to 0.0.7
deblockt Jul 29, 2021
06e770f
fix: startup issue with local_file dependencies
deblockt Oct 31, 2021
dd7d8b7
ci: add release process
deblockt Oct 31, 2021
ba3cebc
ci: upgrade version to 0.0.8
deblockt Oct 31, 2021
9b5c656
feat: first try to add cloud support
deblockt Apr 1, 2022
e3edc3f
doc: add cloud support information
deblockt Apr 2, 2022
e311d50
ci: upgrade version to 0.0.9
deblockt Apr 2, 2022
452d928
feat: get the map from the proscenic cloud
deblockt Apr 12, 2022
bcf3d3b
ci: upgrade version to 0.0.10
deblockt Apr 12, 2022
6045c37
Update README.md
deblockt Apr 12, 2022
ddfed40
fix: timeout issue on proscenic cloud
deblockt Apr 16, 2022
5913040
ci: upgrade version to 0.0.11
deblockt Apr 19, 2022
9c14bd5
docs: update hacs.json
deblockt May 31, 2022
b49263d
docs: update hacs url
wrt54g Jun 3, 2022
e2a8441
fix: python 3.10 compatibility issue
deblockt Jul 9, 2022
af9997d
ci: upgrade version to 0.0.12
deblockt Jul 9, 2022
42a2e70
fix: use StateVacuumEntity instead of VacuumEntity
deblockt Sep 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/hassfest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Validate with hassfest

on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"

jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- uses: home-assistant/actions/hassfest@master
32 changes: 32 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Release

on:
workflow_dispatch:
branches:
- master
inputs:
version:
description: 'the new version number'
required: true

jobs:
release:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- name: "update version number"
run: cat <<< $(jq '.version = "${{ github.event.inputs.version }}"' custom_components/proscenic/manifest.json) > custom_components/proscenic/manifest.json
- name: "commit version update"
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "ci: upgrade version to ${{ github.event.inputs.version }}"
- name: "zip custom_component"
run: cd custom_components/proscenic; zip -r ../../proscenic.zip *
- name: release
uses: ncipollo/release-action@v1
id: create_release
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event.inputs.version }}
artifacts: proscenic.zip
name: version ${{ github.event.inputs.version }}
5 changes: 2 additions & 3 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ jobs:
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/integration/action@master"
uses: "hacs/action@main"
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORY: "integration"
category: "integration"
106 changes: 40 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Home assistant proscenic 790T vacuum integration

the purpose of this integration is to provide an integration of proscenic 790T vacuum.
[![GitHub release](https://img.shields.io/github/release/deblockt/hass-proscenic-790T-vacuum)](https://github.com/deblockt/hass-proscenic-790T-vacuum/releases/latest)
[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/hacs/integration)

The purpose of this integration is to provide an integration of proscenic 790T vacuum.
It allow home assistant to:
- start cleaning
- pause cleaning
Expand All @@ -14,7 +17,7 @@ It allow home assistant to:

### HACS installation

TODO
You can use [HACS](https://hacs.xyz/) to install this component. Search for the Integration "proscenic 790T vacuum"

### Manual installation

Expand All @@ -25,84 +28,55 @@ TODO

## Configuration

To add your vacuum on home assistant, you should add this:

``` yaml
vacuum:
- platform: proscenic
host: "<vacuum-ip>"
deviceId: ""
token: ""
authCode: ""
userId: ""
name: ""
sleep_duration_on_exit: # default 60. number of second waiting before reconnection (if you use proscenic app)
```

deviceId, token and userId can be retrieved using the Proscenic robotic application :
1. On your smartphone, install [Packet capture](https://play.google.com/store/apps/details?id=app.greyshirts.sslcapture&hl=fr)
2. Open Packet capture and start a capture ![screenshot](./doc/packet_capture_button.png) select Proscenic Robotic app
3. Open the proscenic application, and open the vacuum view
4. Reopen Packet capture
1. click on the first line
2. click on the line `<your_vacuum_ip>:8888`
3. get you informations ![screenshot](./doc/packet_with_info.jpg)
5. you can add your vacuum on lovelace ui entities
1. You can simply add it as an entity
2. You can use the [vacuum-card](https://github.com/denysdovhan/vacuum-card)
Add your device via the Integration menu.

## Cleaning map management
[![Open your Home Assistant instance and start setting up a new integration.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=proscenic)

![map](./doc/map.png)
You can choose between two connection mode:
- *local*: the integration will use your local network to contact your vacuum (send command to start/stop). But the cloud will be used to get vacuum status, and the cleaning map.
- *cloud*: All interactions are done using the cloud.

### Configuration
> Note: Some vacuum don't support the local mode.

The vacuum cleaning map can be displayed on lovelace-ui (it will be displayed only after the first vacuum clean process).

to work you should add a camera entity.
### Get authentifications data

``` yaml
camera:
- platform: local_file
name: vacuum_map
file_path: "/tmp/proscenic_vacuum_map.svg"
```
device id, token, user id and authentication code can be retrieved using the Proscenic robotic application :
1. On your android smartphone (no solution for iphone), install [Packet capture](https://play.google.com/store/apps/details?id=app.greyshirts.sslcapture&hl=fr)
2. Open Packet capture and start a capture ![screenshot](./doc/packet_capture_button.png) select Proscenic Robotic app
3. Open the proscenic application, and open the vacuum view
4. Reopen Packet capture
1. Click on the first line
2. Click on the line `47.91.67.181:20008`
3. Get you informations ![screenshot](./doc/packet_with_info.jpg)
5. You can now enter your informations on home assistant
6. You can add your vacuum on lovelace ui entities
1. You can simply add it as an entity
2. You can use the [vacuum-card](https://github.com/denysdovhan/vacuum-card)

You can use this camera on lovelace to show the map.
> **Note**: YAML configuration is deprecated. This will be removed soon.

The default path to generate the map is `/tmp/proscenic_vacuum_map.svg`. You can define another using this configuration :
## Cleaning map management

``` yaml
vacuum:
- platform: proscenic
map_path: "your_custome_map_path"
```
![map](./doc/map.png)

The camera entity will be automaticaly added.
The proscenic cloud is used to generate the map.

### Add to lovelace
> ⚠️ 🚨: updating to 0.0.10 you should remove the integration and re-add it using cloud configuration to keep the map generation working

To display the camera on lovelace, you can :
- use the [vacuum-card](https://github.com/denysdovhan/vacuum-card) configure the card using code editor and add map property `map: camera.vacuum_map`.
``` yaml
entity: vacuum.my_vacuum
image: default
map: camera.vacuum_map
type: 'custom:vacuum-card'
```
## Available attributes

- or use a card of type `picture-entity`
``` yaml
type: picture-entity
entity: vacuum.my_vacuum
camera_image: camera.vacuum_map
aspect_ratio: 100%
show_state: true
show_name: true
tap_action:
action: more-info
```
Theses attributes are available to be displayed on lovelace-ui:
- `clear_area`: number of m2 cleaned
- `clear_duration`: last clean duration in second
- `error_code`: the current error code, if vacuum is on error status
- `error_detail`: the current error message (in english), if vacuum is on error status

## Know issue

- At home assistant startup the vacuum cleaner status is not retrieved. You should perform an action on home assistant to get the vacuum cleaner status.
- At home assistant startup the vacuum cleaner status is not retrieved. You should perform an action on home assistant to get the vacuum cleaner status.
- If you start the proscenic application, the status of the vacuum cleaner will not be refreshed on home assistant for 60 seconds.
- If you start the proscenic application, you will be disconnected 60 seconds later. You can configure this time using `sleep_duration_on_exit` configuration.

[![buymeacoffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/deblockt)
33 changes: 33 additions & 0 deletions custom_components/proscenic/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from .const import get_or_default, DOMAIN, CONF_SLEEP, DEFAULT_CONF_SLEEP, CONF_DEVICE_ID, CONF_TOKEN, CONF_USER_ID, CONF_AUTH_CODE, CONF_TARGET_ID, CONF_CONNECTION_MODE, LOCAL_MODE
from homeassistant.const import CONF_HOST
from .vacuum_proscenic import Vacuum

async def async_setup_entry(hass, entry):
"""Test"""
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = dict(entry.data)

config = dict(entry.data)
conf_sleep = entry.options.get(CONF_SLEEP, DEFAULT_CONF_SLEEP)

auth = {
CONF_DEVICE_ID: config[CONF_DEVICE_ID],
CONF_TOKEN: config[CONF_TOKEN],
CONF_USER_ID: config[CONF_USER_ID],
CONF_AUTH_CODE: config[CONF_AUTH_CODE],
CONF_TARGET_ID: get_or_default(config, CONF_TARGET_ID, config[CONF_DEVICE_ID])
}

ip = get_or_default(config, CONF_HOST, None)
mode = get_or_default(config, CONF_CONNECTION_MODE, LOCAL_MODE)
device = Vacuum(auth, ip, mode, loop = hass.loop, config = {CONF_SLEEP: conf_sleep})

hass.data[DOMAIN][entry.entry_id]['device'] = device

hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, 'vacuum')
)
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, 'camera')
)
return True
56 changes: 56 additions & 0 deletions custom_components/proscenic/camera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""Support for proscenic 790T Vaccum map."""
import logging
import os

from .const import DOMAIN, CONF_DEVICE_ID
from .vacuum_proscenic import WorkState

from homeassistant.components.camera import Camera


_LOGGER = logging.getLogger(__name__)

async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the 790T vacuums map camera."""
config = hass.data[DOMAIN][config_entry.entry_id]
device = config['device']

_LOGGER.debug("Adding 790T Vacuums camera to Home Assistant")
async_add_entities([ProscenicMapCamera(device)], update_before_add = False)

class ProscenicMapCamera(Camera):
"""Representation of a local file camera."""

def __init__(self, device):
"""Initialize Local File Camera component."""
super().__init__()

self._device = device
self.content_type = 'image/svg+xml'

def camera_image(self, width = None, height = None):
"""Return image response."""
if self._device.map_svg:
return self._device.map_svg

return b'<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1"/>'

@property
def name(self):
"""Return the name of this camera."""
return self._device.device_id + '_map'

@property
def extra_state_attributes(self):
"""Return the camera state attributes."""
return {}

@property
def device_info(self):
"""Return the device info."""
return {"identifiers": {(DOMAIN, self._device.device_id)}}

@property
def unique_id(self) -> str:
"""Return an unique ID."""
return "camera" + self._device.device_id
88 changes: 88 additions & 0 deletions custom_components/proscenic/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from homeassistant import config_entries
from .const import DOMAIN

import voluptuous as vol

from homeassistant.core import callback
from homeassistant.const import CONF_HOST
from homeassistant.helpers.selector import SelectSelector

from .const import LOCAL_MODE, CLOUD_MODE, CONF_CONNECTION_MODE, CONF_DEVICE_ID, CONF_TARGET_ID, CONF_TOKEN, CONF_USER_ID, CONF_AUTH_CODE, CONF_SLEEP, DEFAULT_CONF_SLEEP

class ProscenicConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
VERSION = 1

@staticmethod
@callback
def async_get_options_flow(config_entry):
"""Get option flow."""
return ProscenicOptionsFlowHandler(config_entry)

async def async_step_user(self, user_input=None):
schema = {
vol.Required(CONF_CONNECTION_MODE): vol.In(['cloud', 'local'])
}

return self.async_show_form(
step_id='config_mode_selection', data_schema=vol.Schema(schema)
)

async def async_step_config_mode_selection(self, user_input=None):
if user_input is not None:
mode = user_input[CONF_CONNECTION_MODE]
schema = {
vol.Required(CONF_HOST): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_TOKEN): str,
vol.Required(CONF_USER_ID): str,
vol.Required(CONF_AUTH_CODE): str
}

if mode == 'cloud':
schema[vol.Required(CONF_TARGET_ID)] = str

return self.async_show_form(
step_id='config_connection_info', data_schema=vol.Schema(schema)
)

return self.async_step_user(user_input)

async def async_step_config_connection_info(self, user_input=None):
if user_input is not None and CONF_DEVICE_ID in user_input:
return self.async_create_entry(
title="proscenic vacuum configuration",
data= {
CONF_CONNECTION_MODE: CLOUD_MODE if CONF_TARGET_ID in user_input else LOCAL_MODE,
CONF_HOST: user_input[CONF_HOST],
CONF_TARGET_ID: user_input[CONF_TARGET_ID] if CONF_TARGET_ID in user_input else None,
CONF_DEVICE_ID: user_input[CONF_DEVICE_ID],
CONF_TOKEN: user_input[CONF_TOKEN],
CONF_USER_ID: user_input[CONF_USER_ID],
CONF_AUTH_CODE: user_input[CONF_AUTH_CODE]
}
)

return self.async_step_user(user_input)

class ProscenicOptionsFlowHandler(config_entries.OptionsFlow):
"""Handle option."""

def __init__(self, config_entry):
"""Initialize the options flow."""
self.config_entry = config_entry
self._sleep_duration_on_exit = self.config_entry.options.get(
CONF_SLEEP, DEFAULT_CONF_SLEEP
)

async def async_step_init(self, user_input=None):
"""Handle a flow initialized by the user."""
options_schema = vol.Schema(
{
vol.Required(CONF_SLEEP, default = self._sleep_duration_on_exit): int
},
)

if user_input is not None:
return self.async_create_entry(title='proscenic vacuum configuration', data=user_input)

return self.async_show_form(step_id='init', data_schema=options_schema)
Loading