-
-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Get MyStrom device state before checking support #96004
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,24 @@ | |
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| async def _async_get_device_state( | ||
| device: MyStromSwitch | MyStromBulb, ip_address: str | ||
| ) -> None: | ||
| try: | ||
| await device.get_state() | ||
| except MyStromConnectionError as err: | ||
| _LOGGER.error("No route to myStrom plug: %s", ip_address) | ||
| raise ConfigEntryNotReady() from err | ||
|
|
||
|
|
||
| def _get_mystrom_bulb(host: str, mac: str) -> MyStromBulb: | ||
| return MyStromBulb(host, mac) | ||
|
|
||
|
|
||
| def _get_mystrom_switch(host: str) -> MyStromSwitch: | ||
| return MyStromSwitch(host) | ||
|
|
||
|
|
||
| async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
| """Set up myStrom from a config entry.""" | ||
| host = entry.data[CONF_HOST] | ||
|
|
@@ -34,12 +52,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | |
|
|
||
| device_type = info["type"] | ||
| if device_type in [101, 106, 107]: | ||
| device = MyStromSwitch(host) | ||
| device = _get_mystrom_switch(host) | ||
| platforms = PLATFORMS_SWITCH | ||
| elif device_type == 102: | ||
| await _async_get_device_state(device, info["ip"]) | ||
| elif device_type in [102, 105]: | ||
| mac = info["mac"] | ||
| device = MyStromBulb(host, mac) | ||
| device = _get_mystrom_bulb(host, mac) | ||
| platforms = PLATFORMS_BULB | ||
| await _async_get_device_state(device, info["ip"]) | ||
| if device.bulb_type not in ["rgblamp", "strip"]: | ||
| _LOGGER.error( | ||
| "Device %s (%s) is not a myStrom bulb nor myStrom LED Strip", | ||
|
|
@@ -51,12 +71,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | |
| _LOGGER.error("Unsupported myStrom device type: %s", device_type) | ||
| return False | ||
|
|
||
| try: | ||
| await device.get_state() | ||
| except MyStromConnectionError as err: | ||
| _LOGGER.error("No route to myStrom plug: %s", info["ip"]) | ||
| raise ConfigEntryNotReady() from err | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this happening anymore ? This is important logic to make sure we retry if we cannot connect.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see it now, nevermind. |
||
|
|
||
| hass.data.setdefault(DOMAIN, {})[entry.entry_id] = MyStromData( | ||
| device=device, | ||
| info=info, | ||
|
|
@@ -69,10 +83,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | |
| async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
| """Unload a config entry.""" | ||
| device_type = hass.data[DOMAIN][entry.entry_id].info["type"] | ||
| platforms = [] | ||
| if device_type in [101, 106, 107]: | ||
| platforms = PLATFORMS_SWITCH | ||
| elif device_type == 102: | ||
| platforms = PLATFORMS_BULB | ||
| platforms.extend(PLATFORMS_SWITCH) | ||
| elif device_type in [102, 105]: | ||
| platforms.extend(PLATFORMS_BULB) | ||
| if unload_ok := await hass.config_entries.async_unload_platforms(entry, platforms): | ||
| hass.data[DOMAIN].pop(entry.entry_id) | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,172 @@ | ||
| """Tests for the myStrom integration.""" | ||
| from typing import Any, Optional | ||
|
|
||
|
|
||
| def get_default_device_response(device_type: int) -> dict[str, Any]: | ||
| """Return default device response.""" | ||
| return { | ||
| "version": "2.59.32", | ||
| "mac": "6001940376EB", | ||
| "type": device_type, | ||
| "ssid": "personal", | ||
| "ip": "192.168.0.23", | ||
| "mask": "255.255.255.0", | ||
| "gw": "192.168.0.1", | ||
| "dns": "192.168.0.1", | ||
| "static": False, | ||
| "connected": True, | ||
| "signal": 94, | ||
| } | ||
|
|
||
|
|
||
| def get_default_bulb_state() -> dict[str, Any]: | ||
| """Get default bulb state.""" | ||
| return { | ||
| "type": "rgblamp", | ||
| "battery": False, | ||
| "reachable": True, | ||
| "meshroot": True, | ||
| "on": False, | ||
| "color": "46;18;100", | ||
| "mode": "hsv", | ||
| "ramp": 10, | ||
| "power": 0.45, | ||
| "fw_version": "2.58.0", | ||
| } | ||
|
|
||
|
|
||
| def get_default_switch_state() -> dict[str, Any]: | ||
| """Get default switch state.""" | ||
| return { | ||
| "power": 1.69, | ||
| "Ws": 0.81, | ||
| "relay": True, | ||
| "temperature": 24.87, | ||
| "version": "2.59.32", | ||
| "mac": "6001940376EB", | ||
| "ssid": "personal", | ||
| "ip": "192.168.0.23", | ||
| "mask": "255.255.255.0", | ||
| "gw": "192.168.0.1", | ||
| "dns": "192.168.0.1", | ||
| "static": False, | ||
| "connected": True, | ||
| "signal": 94, | ||
| } | ||
|
|
||
|
|
||
| class MyStromDeviceMock: | ||
| """Base device mock.""" | ||
|
|
||
| def __init__(self, state: dict[str, Any]) -> None: | ||
| """Initialize device mock.""" | ||
| self._requested_state = False | ||
| self._state = state | ||
|
|
||
| async def get_state(self) -> None: | ||
| """Set if state is requested.""" | ||
| self._requested_state = True | ||
|
|
||
|
|
||
| class MyStromBulbMock(MyStromDeviceMock): | ||
| """MyStrom Bulb mock.""" | ||
|
|
||
| def __init__(self, mac: str, state: dict[str, Any]) -> None: | ||
| """Initialize bulb mock.""" | ||
| super().__init__(state) | ||
| self.mac = mac | ||
|
|
||
| @property | ||
| def firmware(self) -> Optional[str]: | ||
| """Return current firmware.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["fw_version"] | ||
|
|
||
| @property | ||
| def consumption(self) -> Optional[float]: | ||
| """Return current firmware.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["power"] | ||
|
|
||
| @property | ||
| def color(self) -> Optional[str]: | ||
| """Return current color settings.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["color"] | ||
|
|
||
| @property | ||
| def mode(self) -> Optional[str]: | ||
| """Return current mode.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["mode"] | ||
|
|
||
| @property | ||
| def transition_time(self) -> Optional[int]: | ||
| """Return current transition time (ramp).""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["ramp"] | ||
|
|
||
| @property | ||
| def bulb_type(self) -> Optional[str]: | ||
| """Return the type of the bulb.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["type"] | ||
|
|
||
| @property | ||
| def state(self) -> Optional[bool]: | ||
| """Return the current state of the bulb.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["on"] | ||
|
|
||
|
|
||
| class MyStromSwitchMock(MyStromDeviceMock): | ||
| """MyStrom Switch mock.""" | ||
|
|
||
| @property | ||
| def relay(self) -> Optional[bool]: | ||
| """Return the relay state.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["on"] | ||
|
|
||
| @property | ||
| def consumption(self) -> Optional[float]: | ||
| """Return the current power consumption in mWh.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["power"] | ||
|
|
||
| @property | ||
| def consumedWs(self) -> Optional[float]: | ||
| """The average of energy consumed per second since last report call.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["Ws"] | ||
|
|
||
| @property | ||
| def firmware(self) -> Optional[str]: | ||
| """Return the current firmware.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["version"] | ||
|
|
||
| @property | ||
| def mac(self) -> Optional[str]: | ||
| """Return the MAC address.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["mac"] | ||
|
|
||
| @property | ||
| def temperature(self) -> Optional[float]: | ||
| """Return the current temperature in celsius.""" | ||
| if not self._requested_state: | ||
| return None | ||
| return self._state["temperature"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently use this method to be able to inject mocks in the tests. Any other method would be preferred!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you need to make it a function instead of calling constructor right away like it was ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I want to inject a mock in the tests and I could not figure out how to patch a constructor call. (the mock is now used to mock the behaviour of the external library better, since the current tests arent representing this well)