├── .github └── workflows │ ├── hacs.yaml │ ├── hassfest.yaml │ ├── pytest.yaml │ └── yamllint.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .yamllint ├── LICENSE ├── README.md ├── assets ├── goe_app_settings.jpg └── lovelace-entities-card.png ├── custom_components ├── __init__.py └── goecharger_mqtt │ ├── __init__.py │ ├── binary_sensor.py │ ├── button.py │ ├── config_flow.py │ ├── const.py │ ├── definitions │ ├── __init__.py │ ├── binary_sensor.py │ ├── button.py │ ├── number.py │ ├── select.py │ ├── sensor.py │ └── switch.py │ ├── entity.py │ ├── manifest.json │ ├── number.py │ ├── select.py │ ├── sensor.py │ ├── services.yaml │ ├── strings.json │ ├── switch.py │ └── translations │ └── en.json ├── hacs.json ├── lovelace-entities-card-config.yaml ├── lovelace-entities-card-device.yaml ├── lovelace-entities-card-diagnostics.yaml ├── mqtt-capture.log ├── requirements.test.txt ├── setup.cfg └── tests ├── __init__.py ├── bandit.yaml ├── conftest.py └── test_config_flow.py /.github/workflows/hacs.yaml: -------------------------------------------------------------------------------- 1 | name: HACS 2 | on: # yamllint disable-line rule:truthy 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | schedule: 8 | - cron: '0 0 * * *' 9 | 10 | jobs: 11 | validate: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: hacs/action@main 16 | with: 17 | category: integration 18 | -------------------------------------------------------------------------------- /.github/workflows/hassfest.yaml: -------------------------------------------------------------------------------- 1 | name: Hassfest 2 | 3 | on: # yamllint disable-line rule:truthy 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | schedule: 9 | - cron: "0 0 * * *" 10 | 11 | jobs: 12 | validate: 13 | runs-on: "ubuntu-latest" 14 | steps: 15 | - uses: "actions/checkout@v2" 16 | - uses: home-assistant/actions/hassfest@master 17 | -------------------------------------------------------------------------------- /.github/workflows/pytest.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: # yamllint disable-line rule:truthy 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | schedule: 9 | - cron: "30 16 * * WED" 10 | 11 | jobs: 12 | pytest: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | max-parallel: 4 16 | matrix: 17 | python-version: ["3.9", "3.10"] 18 | 19 | steps: 20 | - uses: actions/checkout@v1 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v1 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install -r requirements.test.txt 30 | 31 | - name: Run pytest 32 | run: | 33 | pytest 34 | -------------------------------------------------------------------------------- /.github/workflows/yamllint.yaml: -------------------------------------------------------------------------------- 1 | name: yamllint 2 | 3 | on: # yamllint disable-line rule:truthy 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | pull_request: 9 | schedule: 10 | - cron: "0 0 * * *" 11 | 12 | jobs: 13 | yamllint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v1 17 | - name: yaml-lint 18 | uses: ibiqlik/action-yamllint@v3 19 | with: 20 | config_file: .yamllint 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | *.bak 6 | 7 | .idea/ 8 | .pytest_cache/* 9 | .coverage 10 | local/* 11 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/asottile/pyupgrade 3 | rev: v2.7.4 4 | hooks: 5 | - id: pyupgrade 6 | args: [--py37-plus] 7 | - repo: https://github.com/psf/black 8 | rev: 20.8b1 9 | hooks: 10 | - id: black 11 | args: 12 | - --safe 13 | - --quiet 14 | files: ^((custom_components|homeassistant|script|tests)/.+)?[^/]+\.py$ 15 | - repo: https://github.com/codespell-project/codespell 16 | rev: v1.17.1 17 | hooks: 18 | - id: codespell 19 | args: 20 | - --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing,hsa 21 | - --skip="./.*,*.csv,*.json" 22 | - --quiet-level=2 23 | exclude_types: [csv, json] 24 | - repo: https://gitlab.com/pycqa/flake8 25 | rev: 3.8.4 26 | hooks: 27 | - id: flake8 28 | additional_dependencies: 29 | - flake8-docstrings==1.5.0 30 | - pydocstyle==5.0.2 31 | files: ^(custom_components|homeassistant|script|tests)/.+\.py$ 32 | - repo: https://github.com/PyCQA/bandit 33 | rev: 1.6.2 34 | hooks: 35 | - id: bandit 36 | args: 37 | - --quiet 38 | - --format=custom 39 | - --configfile=tests/bandit.yaml 40 | files: ^(custom_components|homeassistant|script|tests)/.+\.py$ 41 | - repo: https://github.com/pre-commit/mirrors-isort 42 | rev: v5.6.4 43 | hooks: 44 | - id: isort 45 | - repo: https://github.com/pre-commit/pre-commit-hooks 46 | rev: v3.3.0 47 | hooks: 48 | - id: check-executables-have-shebangs 49 | stages: [manual] 50 | - id: check-json 51 | - repo: https://github.com/pre-commit/mirrors-mypy 52 | rev: v0.790 53 | hooks: 54 | - id: mypy 55 | args: 56 | - --pretty 57 | - --show-error-codes 58 | - --show-error-context 59 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | extends: default 2 | 3 | yaml-files: 4 | - '*.yaml' 5 | - '*.yml' 6 | - '.yamllint' 7 | 8 | ignore: | 9 | /.cache/ 10 | esphome/**/*.pio* 11 | config/automations.yaml 12 | config/known_devices.yaml 13 | config/scenes.yaml 14 | config/google_calendars.yaml 15 | config/custom_components/scheduler 16 | config/custom_components/xiaomi_cloud_map_extractor 17 | config/custom_components/zha_map 18 | config/custom_components/hacs 19 | 20 | rules: 21 | braces: 22 | level: error 23 | min-spaces-inside: 0 24 | max-spaces-inside: 1 25 | min-spaces-inside-empty: -1 26 | max-spaces-inside-empty: -1 27 | brackets: 28 | level: error 29 | min-spaces-inside: 0 30 | max-spaces-inside: 0 31 | min-spaces-inside-empty: -1 32 | max-spaces-inside-empty: -1 33 | colons: 34 | level: error 35 | max-spaces-before: 0 36 | max-spaces-after: 1 37 | commas: 38 | level: error 39 | max-spaces-before: 0 40 | min-spaces-after: 1 41 | max-spaces-after: 1 42 | comments: 43 | level: error 44 | require-starting-space: true 45 | min-spaces-from-content: 2 46 | comments-indentation: disable 47 | document-end: 48 | level: error 49 | present: false 50 | document-start: 51 | level: error 52 | present: false 53 | empty-lines: 54 | level: error 55 | max: 2 56 | max-start: 0 57 | max-end: 1 58 | hyphens: 59 | level: error 60 | max-spaces-after: 1 61 | indentation: 62 | level: error 63 | spaces: 2 64 | indent-sequences: true 65 | check-multi-line-strings: false 66 | key-duplicates: 67 | level: error 68 | line-length: disable 69 | new-line-at-end-of-file: 70 | level: error 71 | new-lines: 72 | level: error 73 | type: unix 74 | trailing-spaces: 75 | level: error 76 | truthy: 77 | level: error 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # homeassistant-goecharger-mqtt 2 | 3 | ![GitHub actions](https://github.com/syssi/homeassistant-goecharger-mqtt/actions/workflows/pytest.yaml/badge.svg) 4 | ![GitHub actions](https://github.com/syssi/homeassistant-goecharger-mqtt/actions/workflows/hassfest.yaml/badge.svg) 5 | ![GitHub actions](https://github.com/syssi/homeassistant-goecharger-mqtt/actions/workflows/hacs.yaml/badge.svg) 6 | ![GitHub stars](https://img.shields.io/github/stars/syssi/homeassistant-goecharger-mqtt) 7 | ![GitHub forks](https://img.shields.io/github/forks/syssi/homeassistant-goecharger-mqtt) 8 | ![GitHub watchers](https://img.shields.io/github/watchers/syssi/homeassistant-goecharger-mqtt) 9 | [!["Buy Me A Coffee"](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg)](https://www.buymeacoffee.com/syssi) 10 | 11 | This is a custom component for Home Assistant to integrate the go-eCharger HOME+, HOMEfix and Gemini using the MQTT API (v2). If you are using the go-eController there's [another project](https://github.com/karloskar/homeassistant-goecontroller-mqtt) covering that. 12 | 13 | ![Lovelace entities card](assets/lovelace-entities-card.png "Lovelace entities card") 14 | 15 | ## Setup and Configuration 16 | 17 | 1. Use HACS to install this custom component 18 | 1. Restart HA 19 | 1. Make sure you have an MQTT Broker ([e.g. Mosquitto broker](https://github.com/eclipse/mosquitto)) and a working [MQTT integration](https://www.home-assistant.io/integrations/mqtt/) in HA 20 | 1. (Recommended) Access to messages on MQTT Broker via client such as [MQTT Explorer](https://mqtt-explorer.com/) 21 | 1. Enable the MQTT API of your charger at the [go-eCharger App](https://play.google.com/store/apps/details?id=co.goe.app&hl=de) 22 | - `Internet` -> `Advanced settings` -> scroll to bottom -> `Enable MQTT API` ([See also here](https://github.com/goecharger/go-eCharger-API-v2/blob/main/mqtt-en.md)) 23 | - at the field `URL` enter your MQTT broker URL, e.g. mqtt://192.168.178.3:1883 for a broker running on a server with IP 192.168.178.3 on default port 1883 24 | ![alt text](assets/goe_app_settings.jpg) 25 | - (optional) Add MQTT keys and certificates as needed 26 | - Press the `SAVE` symbol in the top right to apply the settings 27 | 1. (Optional) Make sure you see a new topic on the MQTT broker using your MQTT client 28 | - New messages appear under `go-eCharger/[your serial number]/` 29 | 1. In HA, add new integration 30 | - `Settings` -> `Devices & services` -> `ADD INTEGRATION` -> `go-eCharger (MQTT)` 31 | - enter serial number (6 digits) of your device (find via App or MQTT client) 32 | - make sure base topic matches what you see in the MQTT broker, in some cases the default `/go-eCharger` has to be changed to `go-eCharger` 33 | 1. See your go-e data pour into HA 34 | 35 | ### Alternative Installation Method (without HACS) 36 | 37 | If you don't want to or cannot use HACS, you can install the integration manually: 38 | 39 | 1. Download the latest release from the [releases page](https://github.com/syssi/homeassistant-goecharger-mqtt/releases) or clone the repository 40 | 2. Copy the directory `/custom_components/goecharger_mqtt` from the repository to the `/custom_components` directory in your Home Assistant configuration folder: 41 | ``` 42 | In your HA config directory: 43 | custom_components 44 | ├── goecharger_mqtt 45 | │ ├── __init__.py 46 | ... 47 | ``` 48 | 3. Continue with step 2 "Restart HA" from the main instructions above 49 | 50 | This manual method achieves the same result as the HACS installation but requires more manual effort and doesn't provide automatic updates like HACS does. 51 | 52 | ## Entities 53 | 54 | ### Binary sensors 55 | 56 | | Topic | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 57 | | ----- | ------------- | -------- | ------------------- | --------- | ------------------ | 58 | | `car` | Car connected | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 59 | | `pha` | Phase L1 after contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 60 | | `pha` | Phase L2 after contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 61 | | `pha` | Phase L3 after contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 62 | | `pha` | Phase L1 before contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 63 | | `pha` | Phase L2 before contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 64 | | `pha` | Phase L3 before contactor | `diagnostic` | :white_large_square: | :heavy_check_mark: | | 65 | | `cca` | Cloud websocket use client auth | `config` | :white_large_square: | :white_large_square: | [^1] | 66 | | `ocuca` | OTA cloud use client auth | `config` | :white_large_square: | :white_large_square: | [^1] | 67 | | `sbe` | Secure boot enabled | | :white_large_square: | :white_large_square: | [^1] | 68 | | `adi` | 16A adapter attached | `diagnostic` | :heavy_check_mark: | :heavy_check_mark: | | 69 | | `cpe` | Charge control requests the cp signal enabled or not immediately | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 70 | | `cpr` | CP enable request | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 71 | | `cws` | Cloud websocket started | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 72 | | `cwsc` | Cloud websocket connected | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 73 | | `fsp` | Force single phase | `diagnostic` | :heavy_check_mark: | :heavy_check_mark: | Is always false. Please use `psm` instead | 74 | | `lwcf` | Last failed WiFi connect | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 75 | | `tlf` | Test charging finished | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 76 | | `tls` | Test charging started | `diagnostic` | :white_large_square: | :white_large_square: | [^1] | 77 | | `sua` | Simulate unplugging permanently | `config` | :white_large_square: | :white_large_square: | [^1] | 78 | 79 | ### Buttons 80 | 81 | | Topic | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 82 | | ----- | ------------- | -------- | ------------------- | --------- | ------------------ | 83 | | `rst` | Restart device | `config` | :heavy_check_mark: | :heavy_check_mark: | | 84 | | `frc` | Force state neutral | `config` | :white_large_square: | :heavy_check_mark: | | 85 | | `frc` | Force state dont charge | `config` | :white_large_square: | :heavy_check_mark: | | 86 | | `frc` | Force state charge | `config` | :white_large_square: | :heavy_check_mark: | | 87 | 88 | ### Sensors 89 | 90 | | Key | Friendly name | Category | Unit | Enabled per default | Supported | Unsupported reason | 91 | | --- | ------------- | -------- | ---- | ------------------- | --------- | ------------------ | 92 | | `+/result` | Last set config key result | `config` | | :heavy_check_mark: | :heavy_check_mark: | | 93 | | `ama` | Maximum current limit | `config` | A | :heavy_check_mark: | :heavy_check_mark: | | 94 | | `ate` | Automatic stop energy | `config` | Wh | :heavy_check_mark: | :heavy_check_mark: | | 95 | | `att` | Automatic stop time | `config` | s | :heavy_check_mark: | :heavy_check_mark: | | 96 | | `awc` | Awattar country | `config` | | :white_large_square: | :white_large_square: | [^1] | 97 | | `awp` | Awattar maximum price threshold | `config` | ¢ | :white_large_square: | :heavy_check_mark: | | 98 | | `cch` | Color charging | `config` | | :white_large_square: | :heavy_check_mark: | | 99 | | `cco` | Car consumption | `config` | | :white_large_square: | :white_large_square: | App only | 100 | | `cfi` | Color finished | `config` | | :white_large_square: | :heavy_check_mark: | | 101 | | `cid` | Color idle | `config` | | :white_large_square: | :heavy_check_mark: | | 102 | | `clp` | Current limit presets | `config` | A | :white_large_square: | :heavy_check_mark: | | 103 | | `ct` | Car type | `config` | | :white_large_square: | :white_large_square: | App only | 104 | | `cwc` | Color wait for car | `config` | | :white_large_square: | :heavy_check_mark: | | 105 | | `fna` | Friendly name | `config` | | :white_large_square: | :white_large_square: | [^1] | 106 | | `frc` | Force state | `config` | | :heavy_check_mark: | :heavy_check_mark: | | 107 | | `frc` | Force state code | `config` | | :white_large_square: | :heavy_check_mark: | | 108 | | `lbr` | LED brightness | `config` | | :white_large_square: | :heavy_check_mark: | | 109 | | `lmo` | Logic mode | `config` | | :heavy_check_mark: | :heavy_check_mark: | | 110 | | `lof` | Load balancing fallback current | `config` | A | :white_large_square: | :white_large_square: | [^1] | 111 | | `log` | Load balancing group id | `config` | | :white_large_square: | :white_large_square: | [^1] | 112 | | `lop` | Load balancing priority | `config` | | :white_large_square: | :white_large_square: | [^1] | 113 | | `lot` | Load balancing total ampere | `config` | A | :white_large_square: | :white_large_square: | [^1] | 114 | | `loty` | Load balancing type | `config` | | :white_large_square: | :white_large_square: | [^1] | 115 | | `map` | Load mapping | `config` | | :white_large_square: | :white_large_square: | [^1] | 116 | | `mca` | Minimum charging current | `config` | A | :heavy_check_mark: | :heavy_check_mark: | | 117 | | `mci` | Minimum charging interval | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 118 | | `mcpd` | Minimum charge pause duration | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 119 | | `mptwt` | Minimum phase toggle wait time | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 120 | | `mpwst` | Minimum phase wish switch time | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 121 | | `pass` | User password | `config` | | :white_large_square: | :white_large_square: | [^1] | 122 | | `psmd` | Force single phase duration | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 123 | | `sch_satur` | Scheduler saturday | `config` | | :white_large_square: | :white_large_square: | [^1] | 124 | | `sch_sund` | Scheduler sunday | `config` | | :white_large_square: | :white_large_square: | [^1] | 125 | | `sch_week` | Scheduler weekday | `config` | | :white_large_square: | :white_large_square: | [^1] | 126 | | `spl3` | Three phase switch level | `config` | W | :heavy_check_mark: | :heavy_check_mark: | | 127 | | `sumd` | Simulate unplugging duration | `config` | ms | :white_large_square: | :white_large_square: | [^1] | 128 | | `tds` | Timezone daylight saving mode | `config` | | :white_large_square: | :white_large_square: | [^1] | 129 | | `tof` | Timezone offset in minutes | `config` | | :white_large_square: | :white_large_square: | [^1] | 130 | | `ts` | Time server | `config` | | :white_large_square: | :white_large_square: | [^1] | 131 | | `tssi` | Time server sync interval | `config` | | :white_large_square: | :white_large_square: | [^1] | 132 | | `tssm` | Time server sync mode | `config` | | :white_large_square: | :white_large_square: | [^1] | 133 | | `tsss` | Time server sync status | `config` | | :white_large_square: | :white_large_square: | [^1] | 134 | | `ust` | Cable unlock mode | `config` | | :heavy_check_mark: | :heavy_check_mark: | | 135 | | `ust` | Cable unlock mode code | `config` | | :white_large_square: | :heavy_check_mark: | | 136 | | `wak` | WiFi accesspoint encryption key | `config` | | :white_large_square: | :white_large_square: | [^1] | 137 | | `wan` | WiFi accesspoint network name | `config` | | :white_large_square: | :white_large_square: | [^1] | 138 | | `wifis` | WiFi configurations | `config` | | :white_large_square: | :white_large_square: | [^1] | 139 | | `apd` | Firmware description | | | :white_large_square: | :white_large_square: | [^1] | 140 | | `arv` | App recommended version | | | :white_large_square: | :white_large_square: | [^1] | 141 | | `ecf` | ESP CPU frequency | | | :white_large_square: | :white_large_square: | [^1] | 142 | | `eci` | ESP Chip info | | | :white_large_square: | :white_large_square: | [^1] | 143 | | `eem` | ESP CPU frequency | | | :white_large_square: | :white_large_square: | [^1] | 144 | | `efi` | ESP Flash info | | | :white_large_square: | :white_large_square: | [^1] | 145 | | `facwak` | WiFi accesspoint key reset value | | | :white_large_square: | :white_large_square: | [^1] | 146 | | `fem` | Flash encryption mode | | | :white_large_square: | :white_large_square: | [^1] | 147 | | `ffna` | Factory friendly name | | | :white_large_square: | :white_large_square: | [^1] | 148 | | `fwan` | Factory WiFi accesspoint network name | | | :white_large_square: | :white_large_square: | [^1] | 149 | | `fwc` | Firmware from car control | | | :white_large_square: | :white_large_square: | [^1] | 150 | | `fwv` | Firmware version | | | :white_large_square: | :heavy_check_mark: | | 151 | | `mod` | Hardware version | | | :white_large_square: | :white_large_square: | [^1] | 152 | | `oem` | Manufacturer | | | :white_large_square: | :white_large_square: | [^1] | 153 | | `otap` | Active OTA partition | | | :white_large_square: | :white_large_square: | [^1] | 154 | | `part` | Partition table | | | :white_large_square: | :white_large_square: | [^1] | 155 | | `pto` | Partition table offset in flash | | | :white_large_square: | :white_large_square: | [^1] | 156 | | `sse` | Serial number | | | :white_large_square: | :white_large_square: | [^1] | 157 | | `typ` | Device type | | | :white_large_square: | :white_large_square: | [^1] | 158 | | `var` | Device variant | | kW | :white_large_square: | :heavy_check_mark: | | 159 | | `del` | Delete card | `config` | | :white_large_square: | :white_large_square: | [^1] | 160 | | `delw` | Delete STA config | `config` | | :white_large_square: | :white_large_square: | [^1] | 161 | | `lrn` | Learn card | `config` | | :white_large_square: | :white_large_square: | [^1] | 162 | | `oct` | Firmware update trigger | `config` | | :white_large_square: | :white_large_square: | [^1] | 163 | | `acu` | Maximum allowed current | `diagnostic` | A | :heavy_check_mark: | :heavy_check_mark: | | 164 | | `amt` | Current temperature limit | `diagnostic` | °C | :heavy_check_mark: | :heavy_check_mark: | | 165 | | `atp` | Next trip plan data | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 166 | | `awcp` | Awattar current price | `diagnostic` | ¢ | :white_large_square: | :heavy_check_mark: | | 167 | | `awpl` | Awattar price list | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 168 | | `car` | Car state | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 169 | | `cbl` | Cable maximum current | `diagnostic` | A | :white_large_square: | :heavy_check_mark: | | 170 | | `ccu` | Charge controller update progress | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 171 | | `ccw` | Connected WiFi | `diagnostic` | | :white_large_square: | :white_large_square: | JSON decoding required. Values non-essential | 172 | | `cdi` | Charging duration | `diagnostic` | ms | :heavy_check_mark: | :heavy_check_mark: | | 173 | | `cdi` | Charging duration counter | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 174 | | `cus` | Cable unlock status code | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 175 | | `cus` | Cable unlock status | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 176 | | `cwsca` | Cloud websocket connected | `diagnostic` | ms | :white_large_square: | :white_large_square: | [^1] | 177 | | `efh` | ESP free heap | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 178 | | `efh32` | ESP free heap 32bit aligned | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 179 | | `efh8` | ESP free heap 8bit aligned | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 180 | | `ehs` | ESP heap size | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 181 | | `emfh` | ESP minimum free heap since boot | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 182 | | `emhb` | ESP maximum size of allocated heap block since boot | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 183 | | `err` | Error | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 184 | | `err` | Error code | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 185 | | `esr` | RTC reset reason | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 186 | | `eto` | Total energy | `diagnostic` | Wh | :heavy_check_mark: | :heavy_check_mark: | | 187 | | `etop` | Total energy persisted | `diagnostic` | Wh | :white_large_square: | :white_large_square: | [^1] | 188 | | `ffb` | Lock feedback | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 189 | | `ffba` | Lock feedback age | `diagnostic` | ms | :white_large_square: | :white_large_square: | [^1] | 190 | | `fhz` | Grid frequency | `diagnostic` | Hz | :white_large_square: | :heavy_check_mark: | | 191 | | `fsptws` | Force single phase toggle wished since | `diagnostic` | ms | :white_large_square: | :white_large_square: | [^1] | 192 | | `host` | Hostname on STA interface | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 193 | | `lbp` | Last button press | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 194 | | `lccfc` | Last car state changed from charging | `diagnostic` | ms | :heavy_check_mark: | :heavy_check_mark: | | 195 | | `lccfi` | Last car state changed from idle | `diagnostic` | ms | :heavy_check_mark: | :heavy_check_mark: | | 196 | | `lcctc` | Last car state changed to charging | `diagnostic` | ms | :heavy_check_mark: | :heavy_check_mark: | | 197 | | `lck` | Effective lock setting | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 198 | | `led` | LED animation details | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 199 | | `lfspt` | Last force single phase toggle | `diagnostic` | ms | :white_large_square: | :white_large_square: | [^1] | 200 | | `lmsc` | Last model status change | `diagnostic` | ms | :white_large_square: | :heavy_check_mark: | | 201 | | `loa` | Load balancing available current | `diagnostic` | A | :heavy_check_mark: | :heavy_check_mark: | | 202 | | `loc` | Local time | `diagnostic` | | :white_large_square: | :white_large_square: | Valueless with a high update interval of 1s | 203 | | `lom` | Load balancing members | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 204 | | `los` | Load balancing status | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 205 | | `lssfc` | WiFi station disconnected since | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 206 | | `lsstc` | WiFi station connected since | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 207 | | `mcpea` | Minimum charge pause ends at | `diagnostic` | ms | :white_large_square: | :white_large_square: | [^1] | 208 | | `mmp` | Maximum measured charging power | `diagnostic` | W | :white_large_square: | :white_large_square: | [^1] | 209 | | `modelStatus` | Status | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 210 | | `modelStatus` | Status code | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 211 | | `msi` | Reason why we allow charging or not | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 212 | | `nrg` | Voltage L1 | `diagnostic` | V | :heavy_check_mark: | :heavy_check_mark: | | 213 | | `nrg` | Voltage L2 | `diagnostic` | V | :heavy_check_mark: | :heavy_check_mark: | | 214 | | `nrg` | Voltage L3 | `diagnostic` | V | :heavy_check_mark: | :heavy_check_mark: | | 215 | | `nrg` | Voltage N | `diagnostic` | V | :heavy_check_mark: | :heavy_check_mark: | | 216 | | `nrg` | Current L1 | `diagnostic` | A | :heavy_check_mark: | :heavy_check_mark: | | 217 | | `nrg` | Current L2 | `diagnostic` | A | :heavy_check_mark: | :heavy_check_mark: | | 218 | | `nrg` | Current L3 | `diagnostic` | A | :heavy_check_mark: | :heavy_check_mark: | | 219 | | `nrg` | Power L1 | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 220 | | `nrg` | Power L2 | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 221 | | `nrg` | Power L3 | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 222 | | `nrg` | Power N | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 223 | | `nrg` | Current power | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 224 | | `nrg` | Power factor L1 | `diagnostic` | % | :heavy_check_mark: | :heavy_check_mark: | | 225 | | `nrg` | Power factor L2 | `diagnostic` | % | :heavy_check_mark: | :heavy_check_mark: | | 226 | | `nrg` | Power factor L3 | `diagnostic` | % | :heavy_check_mark: | :heavy_check_mark: | | 227 | | `nrg` | Power factor N | `diagnostic` | % | :heavy_check_mark: | :heavy_check_mark: | | 228 | | `oca` | OTA cloud app description | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 229 | | `ocl` | OTA from cloud length | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 230 | | `ocm` | OTA from cloud message | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 231 | | `ocp` | OTA from cloud progress | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 232 | | `ocs` | OTA from cloud status | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 233 | | `ocu` | List of available firmware versions | `diagnostic` | | :white_large_square: | :heavy_check_mark: | | 234 | | `onv` | Newest OTA version | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 235 | | `pwm` | Phase wish mode for debugging | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 236 | | `pgrid` | Power from Grid | | | :heavy_check_mark: | :heavy_check_mark: | | 237 | | `ppv` | Power from Solar Panels | | | :heavy_check_mark: | :heavy_check_mark: | | 238 | | `pakku` | Power from External Battery | | | :heavy_check_mark: | :heavy_check_mark: | | 239 | | `qsc` | Queue size cloud | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 240 | | `qsw` | Queue size web | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 241 | | `rbc` | Reboot counter | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 242 | | `rbt` | Uptime | `diagnostic` | | :white_large_square: | :white_large_square: | TODO: Convert to a timestamp first | 243 | | `rcd` | Residual current detection | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 244 | | `rfb` | Relay feedback | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 245 | | `rr` | ESP reset reason | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 246 | | `rssi` | WiFi signal strength | `diagnostic` | dBm | :white_large_square: | :heavy_check_mark: | | 247 | | `scaa` | WiFi scan age | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 248 | | `scan` | WiFi scan result | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 249 | | `scas` | WiFi scan status | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 250 | | `tma` | Temperature sensor 1 | `diagnostic` | °C | :heavy_check_mark: | :heavy_check_mark: | | 251 | | `tma` | Temperature sensor 2 | `diagnostic` | °C | :heavy_check_mark: | :heavy_check_mark: | | 252 | | `tpa` | Total power average | `diagnostic` | W | :heavy_check_mark: | :heavy_check_mark: | | 253 | | `trx` | Transaction | `diagnostic` | | :heavy_check_mark: | :heavy_check_mark: | | 254 | | `tsom` | Time server operating mode | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 255 | | `utc` | UTC time | `diagnostic` | | :white_large_square: | :white_large_square: | Valueless with a high update interval of 1s | 256 | | `wcch` | Clients via http | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 257 | | `wccw` | Clients via websocket | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 258 | | `wh` | Charged energy | `diagnostic` | Wh | :heavy_check_mark: | :heavy_check_mark: | | 259 | | `wsms` | WiFi state machine state | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 260 | | `wst` | WiFi station status | `diagnostic` | | :white_large_square: | :white_large_square: | [^1] | 261 | | `psm` | Configured phases | `config` | | :heavy_check_mark: | :heavy_check_mark: | | 262 | | `cards` | Charged energy card 1 | `diagnostic` | Wh | :heavy_check_mark: | :heavy_check_mark: | | 263 | | `cards` | Charged energy card 2 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 264 | | `cards` | Charged energy card 3 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 265 | | `cards` | Charged energy card 4 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 266 | | `cards` | Charged energy card 5 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 267 | | `cards` | Charged energy card 6 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 268 | | `cards` | Charged energy card 7 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 269 | | `cards` | Charged energy card 8 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 270 | | `cards` | Charged energy card 9 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 271 | | `cards` | Charged energy card 10 | `diagnostic` | Wh | :white_large_square: | :heavy_check_mark: | | 272 | 273 | ### Switch entities 274 | 275 | | Key | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 276 | | --- | ------------- | -------- | ------------------- | --------- | ------------------ | 277 | | `bac` | Allow current change by button | `config` | :heavy_check_mark: | :heavy_check_mark: | | 278 | | `ara` | Automatic stop mode | `config` | :heavy_check_mark: | :heavy_check_mark: | | 279 | | `wen` | WiFi enabled | `config` | :white_large_square: | :white_large_square: | [^1] | 280 | | `tse` | Time server enabled | `config` | :white_large_square: | :white_large_square: | [^1] | 281 | | `sdp` | Button allow force change | `config` | :white_large_square: | :white_large_square: | [^1] | 282 | | `nmo` | Norway mode | `config` | :white_large_square: | :white_large_square: | [^1] | 283 | | `lse` | LED off on standby | `config` | :white_large_square: | :white_large_square: | [^1] | 284 | | `awe` | Awattar mode | `config` | :heavy_check_mark: | :heavy_check_mark: | | 285 | | `acp` | Allow charge pause | `config` | :heavy_check_mark: | :white_large_square: | [^1] | 286 | | `esk` | Energy set | `config` | :white_large_square: | :white_large_square: | App only | 287 | | `fup` | Charge with PV surplus | `config` | :heavy_check_mark: | :heavy_check_mark: | | 288 | | `su` | Simulate unplugging | `config` | :white_large_square: | :white_large_square: | [^1] | 289 | | `hws` | HTTP STA reachable | `config` | :white_large_square: | :white_large_square: | [^1] | 290 | | `hsa` | HTTP STA authentication | `config` | :white_large_square: | :white_large_square: | [^1] | 291 | | `loe` | Load balancing enabled | `config` | :white_large_square: | :white_large_square: | [^1] | 292 | | `upo` | Unlock power outage | `config` | :white_large_square: | :white_large_square: | [^1] | 293 | | `cwe` | Cloud websocket enabled | `config` | :white_large_square: | :white_large_square: | [^1] | 294 | | `psm` | Force single phase | `diagnostic` | :heavy_check_mark: | :heavy_check_mark: | | 295 | | `acs` | Card authorization required | `config` | :heavy_check_mark: | :heavy_check_mark: | | 296 | 297 | ### Number entities 298 | 299 | | Key | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 300 | | --- | ------------- | -------- | ------------------- | --------- | ------------------ | 301 | | `ama` | Maximum current limit | `config` | :heavy_check_mark: | :heavy_check_mark: | | 302 | | `amp` | Requested current | `config` | :heavy_check_mark: | :heavy_check_mark: | | 303 | | `ate` | Automatic stop energy | `config` | :heavy_check_mark: | :heavy_check_mark: | | 304 | | `att` | Automatic stop time | `config` | :heavy_check_mark: | :heavy_check_mark: | | 305 | | `awp` | Awattar maximum price threshold | `config` | :heavy_check_mark: | :heavy_check_mark: | | 306 | | `dwo` | Charging energy limit | `config` | :heavy_check_mark: | :heavy_check_mark: | | 307 | | `lop` | Load balancing priority | `config` | :white_large_square: | :white_large_square: | [^1] | 308 | | `pgt` | Grid target | `config` | :heavy_check_mark: | :heavy_check_mark: | [^2] | 309 | 310 | ### Select entities 311 | 312 | | Key | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 313 | | --- | ------------- | -------- | ------------------- | --------- | ------------------ | 314 | | `lmo` | Logic mode | `config` | :heavy_check_mark: | :heavy_check_mark: | | 315 | | `ust` | Cable unlock mode | `config` | :heavy_check_mark: | :heavy_check_mark: | | 316 | | `frc` | Force state | `config` | :heavy_check_mark: | :heavy_check_mark: | | 317 | | `trx` | Transaction | `config` | :heavy_check_mark: | :heavy_check_mark: | | 318 | 319 | ## Charge with PV Surplus 320 | 321 | ### Setable only PV-surplus entities 322 | 323 | This feature requires firmware 0.55.6 or newer. 324 | 325 | | Key | Friendly name | Category | Enabled per default | Supported | Unsupported reason | 326 | | --- | ------------- | -------- | ------------------- | --------- | ------------------ | 327 | | `ids` | Input avail Power | `config` | :white_large_square: | :heavy_check_mark: | | 328 | 329 | `ids` is used to input values to the ECO PV-surplus charging mode. (PV = Photo Voltaic aka Solar Panels) 330 | 331 | `ids` is set with a JSON list: `{"pGrid":0.0,"pAkku":0.0,"pPv":0.0}` - If values are accepted they can be read back thru the `pgrid`, `pakku` and `ppv` sensors. `pGrid` is required. The others are optional. 332 | 333 | `ids` values decays, so must be updated every 10s or faster. No update for 10-15s means no PV-surplus is available. `pgrid`/`pakku`/`ppv` will thus all become `unknown`. 334 | 335 | Only `pGrid` is used in calculations. Negative `pGrid` means power is exported, and thus available to the charger. Charger is then constantly calculating available power and adjusting charge power up and down multiple times per minute (on every update). If 1/3 phase is set to automatic, it will switch between 1 and 3 phases. The 1->3 phase switch level is set in `spl3` 336 | 337 | By feeding `ids` values, ECO charging can be controlled (on/off) in the go-eCharger App. It is safe and expected to set this value often. 338 | 339 | For PV surplus charging to be enabled, `lmo` (Logic mode) most be set to 4 (Eco mode), and `fup` (Use PV surplus) must be set to true. 340 | 341 | See template example below for how to continuously update `ids` 342 | 343 | #### Automation example 344 | ``` 345 | alias: go-e Surplus Charging 346 | description: "Simple automation to update values needed for using solar surplus with go-e Chargers" 347 | trigger: 348 | - platform: time_pattern 349 | seconds: /5 350 | condition: [] 351 | action: 352 | - service: mqtt.publish 353 | data: 354 | qos: "0" 355 | # Change to your charger ID here 356 | topic: go-eCharger/999999/ids/set 357 | # Please provide your own entities here, as described above 358 | payload: {{'{"pGrid": '}}{{states('sensor.meter_active_power_raw')}}{{', "pPv":'}}{{states('sensor.total_dc_power')}}{{', "pAkku":0}'}} 359 | retain: false 360 | ``` 361 | 362 | ## Platform services 363 | 364 | ### Service `goecharger_mqtt.set_config_key` 365 | 366 | Sets a config `key` to a `value`. 367 | 368 | | Service data attribute | Optional | Description | 369 | |---------------------------|----------|----------------------------------------------------------------------| 370 | | `serial_number` | no | The serial number of the go-e device | 371 | | `key` | no | The key of the config parameter you want to change | 372 | | `value` | no | The new value | 373 | 374 | ## Tips and tricks 375 | 376 | ### How to suspend the access point of the go-e charger 377 | 378 | Per default the WiFi network of the charger is always active even if the device is connected as station to your 379 | WiFi network. If `cloud access` is enabled the API key `wda` can be used to suspend the access point as soon 380 | as the connection to the cloud is established: 381 | 382 | ``` 383 | # Suspend access point mode on cloud connection 384 | curl -s "http://192.168.xx.xx/api/set?wda=true" 385 | 386 | # Pretty print the full status 387 | curl -s "http://192.168.xx.xx/api/status" | json_pp 388 | 389 | # Check the value of the `wda` key 390 | curl -s "http://192.168.1.11/api/status" | jq '.wda' 391 | ``` 392 | 393 | The `wda` key can be changed via the HTTP-API v2 only. The device doesn't accept the setting via MQTT. For more 394 | details please see https://github.com/goecharger/go-eCharger-API-v2/issues/35. 395 | 396 | ## References 397 | 398 | * https://github.com/goecharger/go-eCharger-API-v2/blob/main/mqtt-en.md 399 | * https://github.com/goecharger/go-eCharger-API-v2/blob/main/apikeys-en.md 400 | * https://github.com/boralyl/github-custom-component-tutorial 401 | 402 | [^1]: Not exposed via MQTT in firmware 053.1 403 | [^2]: Exposed via MQTT since firmware 056.2 404 | -------------------------------------------------------------------------------- /assets/goe_app_settings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syssi/homeassistant-goecharger-mqtt/f5eac0220bd03d793c561166ba5897bb755e65a5/assets/goe_app_settings.jpg -------------------------------------------------------------------------------- /assets/lovelace-entities-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syssi/homeassistant-goecharger-mqtt/f5eac0220bd03d793c561166ba5897bb755e65a5/assets/lovelace-entities-card.png -------------------------------------------------------------------------------- /custom_components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/syssi/homeassistant-goecharger-mqtt/f5eac0220bd03d793c561166ba5897bb755e65a5/custom_components/__init__.py -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/__init__.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) integration.""" 2 | from __future__ import annotations 3 | 4 | import logging 5 | 6 | from homeassistant.components import mqtt 7 | from homeassistant.config_entries import ConfigEntry 8 | from homeassistant.core import HomeAssistant, ServiceCall, callback 9 | import homeassistant.helpers.config_validation as cv 10 | from homeassistant.helpers.typing import ConfigType 11 | import voluptuous as vol 12 | 13 | from .const import ( 14 | ATTR_KEY, 15 | ATTR_SERIAL_NUMBER, 16 | ATTR_VALUE, 17 | DEFAULT_TOPIC_PREFIX, 18 | DOMAIN, 19 | ) 20 | 21 | PLATFORMS: list[str] = [ 22 | "binary_sensor", 23 | "button", 24 | "number", 25 | "sensor", 26 | "select", 27 | "switch", 28 | ] 29 | 30 | _LOGGER = logging.getLogger(__name__) 31 | 32 | SERVICE_SCHEMA_SET_CONFIG_KEY = vol.Schema( 33 | { 34 | vol.Required(ATTR_SERIAL_NUMBER): cv.string, 35 | vol.Required(ATTR_KEY): cv.string, 36 | vol.Required(ATTR_VALUE): cv.string, 37 | } 38 | ) 39 | 40 | 41 | async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: 42 | """Set up go-eCharger (MQTT) from a config entry.""" 43 | hass.data.setdefault(DOMAIN, {}) 44 | await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) 45 | 46 | return True 47 | 48 | 49 | async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: 50 | """Unload a config entry.""" 51 | unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) 52 | 53 | return unload_ok 54 | 55 | 56 | async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: 57 | """Set up integration.""" 58 | 59 | @callback 60 | async def set_config_key_service(call: ServiceCall) -> None: 61 | serial_number = call.data.get("serial_number") 62 | key = call.data.get("key") 63 | # @FIXME: Retrieve the topic_prefix from config_entry 64 | topic = f"{DEFAULT_TOPIC_PREFIX}/{serial_number}/{key}/set" 65 | value = call.data.get("value") 66 | 67 | if not value.isnumeric(): 68 | if value in ["true", "True"]: 69 | value = "true" 70 | elif value in ["false", "False"]: 71 | value = "false" 72 | else: 73 | value = f'"{value}"' 74 | 75 | await mqtt.async_publish(hass, topic, value) 76 | 77 | hass.services.async_register( 78 | DOMAIN, 79 | "set_config_key", 80 | set_config_key_service, 81 | schema=SERVICE_SCHEMA_SET_CONFIG_KEY, 82 | ) 83 | 84 | return True 85 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/binary_sensor.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) binary sensor.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.binary_sensor import BinarySensorEntity 7 | from homeassistant.core import callback 8 | 9 | from .definitions.binary_sensor import ( 10 | BINARY_SENSORS, 11 | GoEChargerBinarySensorEntityDescription, 12 | ) 13 | from .entity import GoEChargerEntity 14 | 15 | _LOGGER = logging.getLogger(__name__) 16 | 17 | 18 | async def async_setup_entry( 19 | hass: core.HomeAssistant, 20 | config_entry: config_entries.ConfigEntry, 21 | async_add_entities, 22 | ): 23 | """Config entry setup.""" 24 | 25 | # _LOGGER.debug( 26 | # "| Topic | Friendly name | Category | Enabled per default | Supported | Unsupported reason |" 27 | # ) 28 | # _LOGGER.debug( 29 | # "| ----- | ------------- | -------- | ------------------- | --------- | ------------------ |" 30 | # ) 31 | # for description in BINARY_SENSORS: 32 | # entity_registry_enabled = ( 33 | # ":heavy_check_mark:" 34 | # if description.entity_registry_enabled_default 35 | # else ":white_large_square:" 36 | # ) 37 | # supported = ":heavy_check_mark:" if not description.disabled else ":x:" 38 | # reason = ( 39 | # "[^1]" 40 | # if description.disabled_reason == "Not exposed via MQTT in firmware 053.1" 41 | # else description.disabled_reason 42 | # ) 43 | # entity_category = ( 44 | # "" 45 | # if description.entity_category is None 46 | # else f"`{description.entity_category}`" 47 | # ) 48 | # _LOGGER.debug( 49 | # f"| `{description.key}` | {description.name} | {entity_category} | {entity_registry_enabled} | {supported} | {reason} |" 50 | # ) 51 | 52 | async_add_entities( 53 | GoEChargerBinarySensor(config_entry, description) 54 | for description in BINARY_SENSORS 55 | if not description.disabled 56 | ) 57 | 58 | 59 | class GoEChargerBinarySensor(GoEChargerEntity, BinarySensorEntity): 60 | """Representation of a go-eCharger sensor that is updated via MQTT.""" 61 | 62 | entity_description: GoEChargerBinarySensorEntityDescription 63 | 64 | def __init__( 65 | self, 66 | config_entry: config_entries.ConfigEntry, 67 | description: GoEChargerBinarySensorEntityDescription, 68 | ) -> None: 69 | """Initialize the binary sensor.""" 70 | self.entity_description = description 71 | 72 | super().__init__(config_entry, description) 73 | 74 | @property 75 | def available(self): 76 | """Return True if entity is available.""" 77 | return self._attr_is_on is not None 78 | 79 | async def async_added_to_hass(self): 80 | """Subscribe to MQTT events.""" 81 | 82 | @callback 83 | def message_received(message): 84 | """Handle new MQTT messages.""" 85 | if self.entity_description.state is not None: 86 | self._attr_is_on = self.entity_description.state( 87 | message.payload, self.entity_description.attribute 88 | ) 89 | else: 90 | if message.payload == "true": 91 | self._attr_is_on = True 92 | elif message.payload == "false": 93 | self._attr_is_on = False 94 | else: 95 | self._attr_is_on = None 96 | 97 | self.async_write_ha_state() 98 | 99 | await mqtt.async_subscribe(self.hass, self._topic, message_received, 1) 100 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/button.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) button.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.button import ButtonEntity 7 | 8 | from .definitions.button import BUTTONS, GoEChargerButtonEntityDescription 9 | from .entity import GoEChargerEntity 10 | 11 | _LOGGER = logging.getLogger(__name__) 12 | 13 | 14 | async def async_setup_entry( 15 | hass: core.HomeAssistant, 16 | config_entry: config_entries.ConfigEntry, 17 | async_add_entities, 18 | ): 19 | """Config entry setup.""" 20 | async_add_entities( 21 | GoEChargerButton(config_entry, description) 22 | for description in BUTTONS 23 | if not description.disabled 24 | ) 25 | 26 | 27 | class GoEChargerButton(GoEChargerEntity, ButtonEntity): 28 | """Representation of a go-eCharger button that can be toggled using MQTT.""" 29 | 30 | entity_description: GoEChargerButtonEntityDescription 31 | 32 | def __init__( 33 | self, 34 | config_entry: config_entries.ConfigEntry, 35 | description: GoEChargerButtonEntityDescription, 36 | ) -> None: 37 | """Initialize the binary sensor.""" 38 | self.entity_description = description 39 | 40 | super().__init__(config_entry, description) 41 | 42 | async def async_press(self, **kwargs): 43 | """Turn the device on. 44 | 45 | This method is a coroutine. 46 | """ 47 | await mqtt.async_publish( 48 | self.hass, f"{self._topic}/set", self.entity_description.payload_press 49 | ) 50 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/config_flow.py: -------------------------------------------------------------------------------- 1 | """Config flow for go-eCharger (MQTT) integration.""" 2 | from __future__ import annotations 3 | 4 | import logging 5 | from typing import Any 6 | 7 | from homeassistant import config_entries 8 | from homeassistant.core import HomeAssistant 9 | from homeassistant.data_entry_flow import FlowResult 10 | from homeassistant.exceptions import HomeAssistantError 11 | from homeassistant.helpers import config_validation as cv 12 | import voluptuous as vol 13 | 14 | from .const import CONF_SERIAL_NUMBER, CONF_TOPIC_PREFIX, DEFAULT_TOPIC_PREFIX, DOMAIN 15 | 16 | try: 17 | # < HA 2022.8.0 18 | from homeassistant.components.mqtt import MqttServiceInfo 19 | except ImportError: 20 | # >= HA 2022.8.0 21 | from homeassistant.helpers.service_info.mqtt import MqttServiceInfo 22 | 23 | _LOGGER = logging.getLogger(__name__) 24 | 25 | DEFAULT_NAME = "go-eCharger" 26 | 27 | STEP_USER_DATA_SCHEMA = vol.Schema( 28 | { 29 | vol.Required(CONF_SERIAL_NUMBER): vol.All(cv.string, vol.Length(min=6, max=6)), 30 | vol.Required(CONF_TOPIC_PREFIX, default=DEFAULT_TOPIC_PREFIX): cv.string, 31 | } 32 | ) 33 | 34 | 35 | class PlaceholderHub: 36 | """Placeholder class to make tests pass. 37 | 38 | TODO Remove this placeholder class and replace with things from your PyPI package. 39 | """ 40 | 41 | def __init__(self, topic_prefix: str, serial_number: str) -> None: 42 | """Initialize.""" 43 | self.topic_prefix = topic_prefix 44 | self.serial_number = serial_number 45 | 46 | async def validate_device_topic(self) -> bool: 47 | """Test if we can authenticate with the host.""" 48 | return True 49 | 50 | 51 | async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]: 52 | """Validate the user input allows us to connect. 53 | 54 | Data has the keys from STEP_USER_DATA_SCHEMA with values provided by the user. 55 | """ 56 | serial_number = data[CONF_SERIAL_NUMBER] 57 | hub = PlaceholderHub(data[CONF_TOPIC_PREFIX], serial_number) 58 | 59 | if not await hub.validate_device_topic(): 60 | raise CannotConnect 61 | 62 | return {"title": f"{DEFAULT_NAME} {serial_number}"} 63 | 64 | 65 | class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): 66 | """Handle a config flow for go-eCharger (MQTT).""" 67 | 68 | VERSION = 1 69 | 70 | def __init__(self) -> None: 71 | """Initialize flow.""" 72 | self._serial_number = None 73 | self._topic_prefix = None 74 | 75 | async def async_step_mqtt(self, discovery_info: MqttServiceInfo) -> FlowResult: 76 | """Handle a flow initialized by MQTT discovery.""" 77 | subscribed_topic = discovery_info.subscribed_topic 78 | 79 | # Subscribed topic must be in sync with the manifest.json 80 | assert subscribed_topic in ["/go-eCharger/+/var", "go-eCharger/+/var"] 81 | 82 | # Example topic: /go-eCharger/072246/var 83 | topic = discovery_info.topic 84 | (prefix, suffix) = subscribed_topic.split("+", 2) 85 | self._serial_number = topic.replace(prefix, "").replace(suffix, "") 86 | self._topic_prefix = prefix[:-1] 87 | 88 | if not self._serial_number.isnumeric(): 89 | return self.async_abort(reason="invalid_discovery_info") 90 | 91 | await self.async_set_unique_id(self._serial_number) 92 | self._abort_if_unique_id_configured() 93 | 94 | return await self.async_step_discovery_confirm() 95 | 96 | async def async_step_discovery_confirm( 97 | self, user_input: dict[str, Any] | None = None 98 | ) -> FlowResult: 99 | """Confirm the setup.""" 100 | name = f"{DEFAULT_NAME} {self._serial_number}" 101 | self.context["title_placeholders"] = {"name": name} 102 | 103 | if user_input is not None: 104 | return self.async_create_entry( 105 | title=name, 106 | data={ 107 | CONF_SERIAL_NUMBER: self._serial_number, 108 | CONF_TOPIC_PREFIX: self._topic_prefix, 109 | }, 110 | ) 111 | 112 | self._set_confirm_only() 113 | return self.async_show_form( 114 | step_id="discovery_confirm", 115 | description_placeholders={"name": name}, 116 | ) 117 | 118 | async def async_step_user( 119 | self, user_input: dict[str, Any] | None = None 120 | ) -> FlowResult: 121 | """Handle the initial step.""" 122 | if user_input is None: 123 | return self.async_show_form( 124 | step_id="user", data_schema=STEP_USER_DATA_SCHEMA 125 | ) 126 | 127 | errors = {} 128 | 129 | try: 130 | info = await validate_input(self.hass, user_input) 131 | except CannotConnect: 132 | errors["base"] = "cannot_connect" 133 | except InvalidAuth: 134 | errors["base"] = "invalid_auth" 135 | except Exception: # pylint: disable=broad-except 136 | _LOGGER.exception("Unexpected exception") 137 | errors["base"] = "unknown" 138 | else: 139 | await self.async_set_unique_id(user_input[CONF_SERIAL_NUMBER]) 140 | self._abort_if_unique_id_configured() 141 | 142 | return self.async_create_entry(title=info["title"], data=user_input) 143 | 144 | return self.async_show_form( 145 | step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors 146 | ) 147 | 148 | 149 | class CannotConnect(HomeAssistantError): 150 | """Error to indicate we cannot connect.""" 151 | 152 | 153 | class InvalidAuth(HomeAssistantError): 154 | """Error to indicate there is invalid auth.""" 155 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/const.py: -------------------------------------------------------------------------------- 1 | """Constants for the go-eCharger (MQTT) integration.""" 2 | 3 | DOMAIN = "goecharger_mqtt" 4 | 5 | ATTR_SERIAL_NUMBER = "serial_number" 6 | ATTR_KEY = "key" 7 | ATTR_VALUE = "value" 8 | 9 | CONF_SERIAL_NUMBER = "serial_number" 10 | CONF_TOPIC_PREFIX = "topic_prefix" 11 | 12 | DEFAULT_TOPIC_PREFIX = "go-eCharger" 13 | 14 | DEVICE_INFO_MANUFACTURER = "go-e" 15 | DEVICE_INFO_MODEL = "go-eCharger HOME" 16 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/__init__.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger sensors exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from collections.abc import Callable 5 | from dataclasses import dataclass 6 | import logging 7 | 8 | from homeassistant.helpers.entity import EntityDescription 9 | 10 | _LOGGER = logging.getLogger(__name__) 11 | 12 | 13 | class GoEChargerStatusCodes: 14 | """Status code container.""" 15 | 16 | car = { 17 | 0: "", 18 | 1: "Idle", 19 | 2: "Charging", 20 | 3: "Wait for car", 21 | 4: "Complete", 22 | 5: "Error", 23 | } 24 | 25 | cus = { 26 | 0: "Unknown", 27 | 1: "Unlocked", 28 | 2: "Unlock failed", 29 | 3: "Locked", 30 | 4: "Lock failed", 31 | 5: "Lock Unlock Powerout", 32 | } 33 | 34 | err = { 35 | 0: "", 36 | 1: "Residual current circuit breaker", 37 | 2: "FiDC", 38 | 3: "Phase fault", 39 | 4: "Over voltage", 40 | 5: "Over current", 41 | 6: "Diode", 42 | 7: "Pp Invalid", 43 | 8: "No ground", 44 | 9: "Contactor Stuck", 45 | 10: "Contactor Missing", 46 | 11: "FiUnknown", 47 | 12: "Unknown", 48 | 13: "Over temperature", 49 | 14: "No Comm", 50 | 15: "Lock Stuck Open", 51 | 16: "Lock Stuck Locked", 52 | 17: "Reserved20", 53 | 18: "Reserved21", 54 | 19: "Reserved22", 55 | 20: "Reserved23", 56 | 21: "Reserved24", 57 | } 58 | 59 | modelStatus = { 60 | 0: "Not charging because no charge control data", 61 | 1: "Not charging because of over temperature", 62 | 2: "Not charging because access control wait", 63 | 3: "Charging because of forced ON", 64 | 4: "Not charging because of forced OFF", 65 | 5: "Not charging because of scheduler", 66 | 6: "Not charging because of energy limit", 67 | 7: "Charging because Awattar price under threshold", 68 | 8: "Charging because of automatic stop test charging", 69 | 9: "Charging because of automatic stop not enough time", 70 | 10: "Charging because of automatic stop", 71 | 11: "Charging because of automatic stop no clock", 72 | 12: "Charging because of PV surplus", 73 | 13: "Charging because of fallback (GoE Default)", 74 | 14: "Charging because of fallback (GoE Scheduler)", 75 | 15: "Charging because of fallback (Default)", 76 | 16: "Not charging because of fallback (GoE Awattar)", 77 | 17: "Not charging because of fallback (Awattar)", 78 | 18: "Not charging because of fallback (Automatic Stop)", 79 | 19: "Charging because of car compatibility (Keep Alive)", 80 | 20: "Charging because charge pause not allowed", 81 | 21: "Unknown", 82 | 22: "Not charging because simulate unplugging", 83 | 23: "Not charging because of phase switch", 84 | 24: "Not charging because of minimum pause duration", 85 | } 86 | 87 | ust = { 88 | 0: "Normal", 89 | 1: "Auto Unlock", 90 | 2: "Always Locked", 91 | 3: "Force Unlock", 92 | } 93 | 94 | frc = { 95 | 0: "Neutral", 96 | 1: "Don't charge", 97 | 2: "Charge", 98 | } 99 | 100 | lmo = { 101 | 3: "Default", 102 | 4: "Awattar", 103 | 5: "Automatic Stop", 104 | } 105 | 106 | psm = { 107 | 1: "1 Phase", 108 | 2: "3 Phases", 109 | } 110 | 111 | 112 | @dataclass 113 | class GoEChargerEntityDescription(EntityDescription): 114 | """Generic entity description for go-eCharger.""" 115 | 116 | state: Callable | None = None 117 | attribute: str = "0" 118 | domain: str = "generic" 119 | disabled: bool | None = None 120 | disabled_reason: str | None = None 121 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/binary_sensor.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger binary sensors exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import json 6 | import logging 7 | 8 | from homeassistant.components.binary_sensor import BinarySensorEntityDescription 9 | from homeassistant.helpers.entity import EntityCategory 10 | 11 | from . import GoEChargerEntityDescription 12 | 13 | _LOGGER = logging.getLogger(__name__) 14 | 15 | 16 | @dataclass 17 | class GoEChargerBinarySensorEntityDescription( 18 | GoEChargerEntityDescription, BinarySensorEntityDescription 19 | ): 20 | """Binary sensor entity description for go-eCharger.""" 21 | 22 | domain: str = "binary_sensor" 23 | 24 | 25 | def extract_item_from_array_to_bool(value, key) -> bool: 26 | """Extract item from array to int.""" 27 | return bool(json.loads(value)[int(key)]) 28 | 29 | 30 | def map_car_idle_to_bool(value, key) -> bool: 31 | """Extract item from array to int.""" 32 | return int(value) > int(key) 33 | 34 | 35 | BINARY_SENSORS: tuple[GoEChargerBinarySensorEntityDescription, ...] = ( 36 | GoEChargerBinarySensorEntityDescription( 37 | key="car", 38 | name="Car connected", 39 | attribute="1", 40 | state=map_car_idle_to_bool, 41 | entity_category=EntityCategory.DIAGNOSTIC, 42 | device_class=None, 43 | icon="mdi:car", 44 | entity_registry_enabled_default=True, 45 | disabled=False, 46 | ), 47 | GoEChargerBinarySensorEntityDescription( 48 | key="pha", 49 | name="Phase L1 after contactor", 50 | attribute="0", 51 | state=extract_item_from_array_to_bool, 52 | entity_category=EntityCategory.DIAGNOSTIC, 53 | device_class=None, 54 | entity_registry_enabled_default=False, 55 | disabled=False, 56 | ), 57 | GoEChargerBinarySensorEntityDescription( 58 | key="pha", 59 | name="Phase L2 after contactor", 60 | attribute="1", 61 | state=extract_item_from_array_to_bool, 62 | entity_category=EntityCategory.DIAGNOSTIC, 63 | device_class=None, 64 | entity_registry_enabled_default=False, 65 | disabled=False, 66 | ), 67 | GoEChargerBinarySensorEntityDescription( 68 | key="pha", 69 | name="Phase L3 after contactor", 70 | attribute="2", 71 | state=extract_item_from_array_to_bool, 72 | entity_category=EntityCategory.DIAGNOSTIC, 73 | device_class=None, 74 | entity_registry_enabled_default=False, 75 | disabled=False, 76 | ), 77 | GoEChargerBinarySensorEntityDescription( 78 | key="pha", 79 | name="Phase L1 before contactor", 80 | attribute="3", 81 | state=extract_item_from_array_to_bool, 82 | entity_category=EntityCategory.DIAGNOSTIC, 83 | device_class=None, 84 | entity_registry_enabled_default=False, 85 | disabled=False, 86 | ), 87 | GoEChargerBinarySensorEntityDescription( 88 | key="pha", 89 | name="Phase L2 before contactor", 90 | attribute="4", 91 | state=extract_item_from_array_to_bool, 92 | entity_category=EntityCategory.DIAGNOSTIC, 93 | device_class=None, 94 | entity_registry_enabled_default=False, 95 | disabled=False, 96 | ), 97 | GoEChargerBinarySensorEntityDescription( 98 | key="pha", 99 | name="Phase L3 before contactor", 100 | attribute="5", 101 | state=extract_item_from_array_to_bool, 102 | entity_category=EntityCategory.DIAGNOSTIC, 103 | device_class=None, 104 | entity_registry_enabled_default=False, 105 | disabled=False, 106 | ), 107 | GoEChargerBinarySensorEntityDescription( 108 | key="cca", 109 | name="Cloud websocket use client auth", 110 | entity_category=None, 111 | device_class=None, 112 | entity_registry_enabled_default=False, 113 | disabled=True, 114 | disabled_reason="Not exposed via MQTT in firmware 053.1", 115 | ), 116 | GoEChargerBinarySensorEntityDescription( 117 | key="ocuca", 118 | name="OTA cloud use client auth", 119 | entity_category=None, 120 | device_class=None, 121 | entity_registry_enabled_default=False, 122 | disabled=True, 123 | disabled_reason="Not exposed via MQTT in firmware 053.1", 124 | ), 125 | GoEChargerBinarySensorEntityDescription( 126 | key="sbe", 127 | name="Secure boot enabled", 128 | entity_category=None, 129 | device_class=None, 130 | entity_registry_enabled_default=False, 131 | disabled=True, 132 | disabled_reason="Not exposed via MQTT in firmware 053.1", 133 | ), 134 | GoEChargerBinarySensorEntityDescription( 135 | key="adi", 136 | name="16A adapter used", 137 | entity_category=EntityCategory.DIAGNOSTIC, 138 | device_class=None, 139 | entity_registry_enabled_default=True, 140 | disabled=False, 141 | ), 142 | GoEChargerBinarySensorEntityDescription( 143 | key="cpe", 144 | name="Charge control requests the cp signal enabled or not immediately", 145 | entity_category=EntityCategory.DIAGNOSTIC, 146 | device_class=None, 147 | entity_registry_enabled_default=False, 148 | disabled=True, 149 | disabled_reason="Not exposed via MQTT in firmware 053.1", 150 | ), 151 | GoEChargerBinarySensorEntityDescription( 152 | key="cpr", 153 | name="CP enable request", 154 | entity_category=EntityCategory.DIAGNOSTIC, 155 | device_class=None, 156 | entity_registry_enabled_default=False, 157 | disabled=True, 158 | disabled_reason="Not exposed via MQTT in firmware 053.1", 159 | ), 160 | GoEChargerBinarySensorEntityDescription( 161 | key="cws", 162 | name="Cloud websocket started", 163 | entity_category=EntityCategory.DIAGNOSTIC, 164 | device_class=None, 165 | entity_registry_enabled_default=False, 166 | disabled=True, 167 | disabled_reason="Not exposed via MQTT in firmware 053.1", 168 | ), 169 | GoEChargerBinarySensorEntityDescription( 170 | key="cwsc", 171 | name="Cloud websocket connected", 172 | entity_category=EntityCategory.DIAGNOSTIC, 173 | device_class=None, 174 | entity_registry_enabled_default=False, 175 | disabled=True, 176 | disabled_reason="Not exposed via MQTT in firmware 053.1", 177 | ), 178 | GoEChargerBinarySensorEntityDescription( 179 | key="fsp", 180 | name="Force single phase", 181 | entity_category=EntityCategory.DIAGNOSTIC, 182 | device_class=None, 183 | entity_registry_enabled_default=True, 184 | disabled=False, 185 | disabled_reason="Is always false. Please use `psm` instead", 186 | ), 187 | GoEChargerBinarySensorEntityDescription( 188 | key="lwcf", 189 | name="Last failed WiFi connect", 190 | entity_category=EntityCategory.DIAGNOSTIC, 191 | device_class=None, 192 | entity_registry_enabled_default=False, 193 | disabled=True, 194 | disabled_reason="Not exposed via MQTT in firmware 053.1", 195 | ), 196 | GoEChargerBinarySensorEntityDescription( 197 | key="tlf", 198 | name="Test charging finished", 199 | entity_category=EntityCategory.DIAGNOSTIC, 200 | device_class=None, 201 | entity_registry_enabled_default=False, 202 | disabled=True, 203 | disabled_reason="Not exposed via MQTT in firmware 053.1", 204 | ), 205 | GoEChargerBinarySensorEntityDescription( 206 | key="tls", 207 | name="Test charging started", 208 | entity_category=EntityCategory.DIAGNOSTIC, 209 | device_class=None, 210 | entity_registry_enabled_default=False, 211 | disabled=True, 212 | disabled_reason="Not exposed via MQTT in firmware 053.1", 213 | ), 214 | ) 215 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/button.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger buttons exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import logging 6 | 7 | from homeassistant.components.button import ButtonEntityDescription 8 | from homeassistant.helpers.entity import EntityCategory 9 | 10 | from . import GoEChargerEntityDescription 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | @dataclass 16 | class GoEChargerButtonEntityDescription( 17 | GoEChargerEntityDescription, ButtonEntityDescription 18 | ): 19 | """Button entity description for go-eCharger.""" 20 | 21 | domain: str = "button" 22 | payload_press: str = "true" 23 | 24 | 25 | BUTTONS: tuple[GoEChargerButtonEntityDescription, ...] = ( 26 | GoEChargerButtonEntityDescription( 27 | key="rst", 28 | name="Restart device", 29 | payload_press="true", 30 | entity_category=EntityCategory.CONFIG, 31 | device_class=None, 32 | icon="mdi:restart", 33 | entity_registry_enabled_default=True, 34 | disabled=False, 35 | ), 36 | GoEChargerButtonEntityDescription( 37 | key="frc", 38 | name="Force state neutral", 39 | attribute="0", 40 | payload_press="0", 41 | entity_category=EntityCategory.CONFIG, 42 | device_class=None, 43 | icon="mdi:auto-fix", 44 | entity_registry_enabled_default=False, 45 | disabled=False, 46 | ), 47 | GoEChargerButtonEntityDescription( 48 | key="frc", 49 | name="Force state dont charge", 50 | attribute="1", 51 | payload_press="1", 52 | entity_category=EntityCategory.CONFIG, 53 | device_class=None, 54 | icon="mdi:auto-fix", 55 | entity_registry_enabled_default=False, 56 | disabled=False, 57 | ), 58 | GoEChargerButtonEntityDescription( 59 | key="frc", 60 | name="Force state charge", 61 | attribute="2", 62 | payload_press="2", 63 | entity_category=EntityCategory.CONFIG, 64 | device_class=None, 65 | icon="mdi:auto-fix", 66 | entity_registry_enabled_default=False, 67 | disabled=False, 68 | ), 69 | ) 70 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/number.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger numbers exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import logging 6 | 7 | from homeassistant.components.number import NumberDeviceClass, NumberEntityDescription 8 | from homeassistant.const import ( 9 | CURRENCY_CENT, 10 | UnitOfElectricCurrent, 11 | UnitOfEnergy, 12 | UnitOfPower, 13 | UnitOfTime, 14 | ) 15 | from homeassistant.helpers.entity import EntityCategory 16 | 17 | from . import GoEChargerEntityDescription 18 | 19 | _LOGGER = logging.getLogger(__name__) 20 | 21 | 22 | @dataclass 23 | class GoEChargerNumberEntityDescription( 24 | GoEChargerEntityDescription, NumberEntityDescription 25 | ): 26 | """Number entity description for go-eCharger.""" 27 | 28 | domain: str = "number" 29 | treat_zero_as_null: bool = False 30 | 31 | 32 | NUMBERS: tuple[GoEChargerNumberEntityDescription, ...] = ( 33 | GoEChargerNumberEntityDescription( 34 | key="ama", 35 | name="Maximum current limit", 36 | entity_category=EntityCategory.CONFIG, 37 | device_class=NumberDeviceClass.CURRENT, 38 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 39 | entity_registry_enabled_default=True, 40 | disabled=False, 41 | native_max_value=32, 42 | native_min_value=6, 43 | native_step=1, 44 | ), 45 | GoEChargerNumberEntityDescription( 46 | key="amp", 47 | name="Requested current", 48 | entity_category=EntityCategory.CONFIG, 49 | device_class=NumberDeviceClass.CURRENT, 50 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 51 | entity_registry_enabled_default=True, 52 | disabled=False, 53 | native_max_value=32, 54 | native_min_value=6, 55 | native_step=1, 56 | ), 57 | GoEChargerNumberEntityDescription( 58 | key="ate", 59 | name="Automatic stop energy", 60 | entity_category=EntityCategory.CONFIG, 61 | device_class=NumberDeviceClass.ENERGY, 62 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 63 | entity_registry_enabled_default=True, 64 | disabled=False, 65 | native_max_value=100000, 66 | native_min_value=1, 67 | native_step=1, 68 | ), 69 | GoEChargerNumberEntityDescription( 70 | key="pgt", 71 | name="Grid Target", 72 | entity_category=EntityCategory.CONFIG, 73 | device_class=None, 74 | native_unit_of_measurement=UnitOfPower.WATT, 75 | entity_registry_enabled_default=True, 76 | disabled=False, 77 | native_max_value=10000, 78 | native_min_value=-10000, 79 | native_step=1, 80 | ), 81 | GoEChargerNumberEntityDescription( 82 | key="att", 83 | name="Automatic stop time", 84 | entity_category=EntityCategory.CONFIG, 85 | device_class=None, 86 | native_unit_of_measurement=UnitOfTime.SECONDS, 87 | entity_registry_enabled_default=True, 88 | disabled=False, 89 | native_max_value=86400, 90 | native_min_value=60, 91 | native_step=1, 92 | ), 93 | GoEChargerNumberEntityDescription( 94 | key="awp", 95 | name="Awattar maximum price threshold", 96 | entity_category=EntityCategory.CONFIG, 97 | device_class=None, 98 | native_unit_of_measurement=CURRENCY_CENT, 99 | entity_registry_enabled_default=True, 100 | disabled=False, 101 | native_max_value=100, 102 | native_min_value=-100, 103 | native_step=0.1, 104 | ), 105 | GoEChargerNumberEntityDescription( 106 | key="dwo", 107 | name="Charging energy limit", 108 | entity_category=EntityCategory.CONFIG, 109 | device_class=NumberDeviceClass.ENERGY, 110 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 111 | entity_registry_enabled_default=True, 112 | disabled=False, 113 | native_max_value=1000000, 114 | native_min_value=0, 115 | native_step=1, 116 | treat_zero_as_null=True, 117 | ), 118 | GoEChargerNumberEntityDescription( 119 | key="lop", 120 | name="Load balancing priority", 121 | entity_category=EntityCategory.CONFIG, 122 | device_class=None, 123 | native_unit_of_measurement=None, 124 | entity_registry_enabled_default=False, 125 | disabled=True, 126 | native_max_value=99, 127 | native_min_value=1, 128 | native_step=1, 129 | ), 130 | ) 131 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/select.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger select entities exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import logging 6 | 7 | from homeassistant.components.select import SelectEntityDescription 8 | from homeassistant.helpers.entity import EntityCategory 9 | 10 | from . import GoEChargerEntityDescription 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | @dataclass 16 | class GoEChargerSelectEntityDescription( 17 | GoEChargerEntityDescription, SelectEntityDescription 18 | ): 19 | """Select entity description for go-eCharger.""" 20 | 21 | legacy_options: dict[str, str] | None = None 22 | domain: str = "select" 23 | 24 | 25 | SELECTS: tuple[GoEChargerSelectEntityDescription, ...] = ( 26 | GoEChargerSelectEntityDescription( 27 | key="lmo", 28 | name="Logic mode", 29 | legacy_options={ 30 | "3": "Default", 31 | "4": "Eco mode", 32 | "5": "Automatic Stop", 33 | }, 34 | entity_category=EntityCategory.CONFIG, 35 | device_class=None, 36 | entity_registry_enabled_default=True, 37 | disabled=False, 38 | ), 39 | GoEChargerSelectEntityDescription( 40 | key="ust", 41 | name="Cable unlock mode", 42 | legacy_options={ 43 | "0": "Normal", 44 | "1": "Auto Unlock", 45 | "2": "Always Locked", 46 | }, 47 | attribute="ust", 48 | entity_category=EntityCategory.CONFIG, 49 | device_class=None, 50 | icon="mdi:account-lock-open", 51 | entity_registry_enabled_default=True, 52 | disabled=False, 53 | ), 54 | GoEChargerSelectEntityDescription( 55 | key="frc", 56 | name="Force state", 57 | legacy_options={ 58 | "0": "Neutral", 59 | "1": "Don't charge", 60 | "2": "Charge", 61 | }, 62 | attribute="frc", 63 | entity_category=EntityCategory.CONFIG, 64 | device_class=None, 65 | icon="mdi:auto-fix", 66 | entity_registry_enabled_default=True, 67 | disabled=False, 68 | ), 69 | GoEChargerSelectEntityDescription( 70 | key="trx", 71 | name="Transaction", 72 | legacy_options={ 73 | "null": "None", 74 | "0": "Without card", 75 | "1": "Card 0", 76 | "2": "Card 1", 77 | "3": "Card 2", 78 | "4": "Card 3", 79 | "5": "Card 4", 80 | "6": "Card 5", 81 | "7": "Card 6", 82 | "8": "Card 7", 83 | "9": "Card 8", 84 | "10": "Card 9", 85 | }, 86 | attribute="trx", 87 | entity_category=EntityCategory.CONFIG, 88 | device_class=None, 89 | icon="mdi:message-text-lock-outline", 90 | entity_registry_enabled_default=True, 91 | disabled=False, 92 | ), 93 | GoEChargerSelectEntityDescription( 94 | key="psm", 95 | name="Phase switch mode", 96 | legacy_options={ 97 | "0": "Auto", 98 | "1": "Force single phase", 99 | "2": "Force three phases", 100 | }, 101 | attribute="psm", 102 | entity_category=EntityCategory.CONFIG, 103 | device_class=None, 104 | icon="mdi:speedometer", 105 | entity_registry_enabled_default=True, 106 | disabled=False, 107 | ), 108 | ) 109 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/sensor.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger sensors exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import json 6 | import logging 7 | 8 | from homeassistant.components.sensor import ( 9 | SensorDeviceClass, 10 | SensorEntityDescription, 11 | SensorStateClass, 12 | ) 13 | from homeassistant.const import ( 14 | CURRENCY_CENT, 15 | PERCENTAGE, 16 | SIGNAL_STRENGTH_DECIBELS, 17 | UnitOfElectricCurrent, 18 | UnitOfElectricPotential, 19 | UnitOfEnergy, 20 | UnitOfFrequency, 21 | UnitOfPower, 22 | UnitOfTemperature, 23 | UnitOfTime, 24 | ) 25 | from homeassistant.helpers.entity import EntityCategory 26 | 27 | from . import GoEChargerEntityDescription, GoEChargerStatusCodes 28 | 29 | _LOGGER = logging.getLogger(__name__) 30 | 31 | 32 | @dataclass 33 | class GoEChargerSensorEntityDescription( 34 | GoEChargerEntityDescription, SensorEntityDescription 35 | ): 36 | """Sensor entity description for go-eCharger.""" 37 | 38 | domain: str = "sensor" 39 | 40 | 41 | def extract_charging_duration(value, attribute) -> int | None: 42 | """Extract charging duration from object. 43 | 44 | Example value: {"type":1,"value":0} 45 | """ 46 | data = json.loads(value) 47 | if "type" in data and data["type"] == int(attribute): 48 | return data["value"] 49 | 50 | return None 51 | 52 | 53 | def extract_energy_from_cards(value, key) -> int | None: 54 | """Extract energy from selected card of the cards object. 55 | 56 | Example value: [{"name":"User 1","energy":0,"cardId":true},{...}, ...] 57 | """ 58 | try: 59 | data = json.loads(value)[int(key)] 60 | return data.get("energy") 61 | except IndexError: 62 | return None 63 | 64 | 65 | def remove_quotes(value, unused): 66 | """Remove quotes helper.""" 67 | return value.replace('"', "") 68 | 69 | 70 | def json_array_to_csv(value, unused) -> str: 71 | """Transform JSON array to CSV.""" 72 | if value == "null": 73 | return "" 74 | 75 | return ", ".join(json.loads(value)) 76 | 77 | 78 | def extract_item_from_array_to_float(value, key) -> float: 79 | """Extract item from array to float.""" 80 | return float(json.loads(value)[int(key)]) 81 | 82 | 83 | def extract_item_from_array_to_int(value, key) -> int: 84 | """Extract item from array to int.""" 85 | return int(json.loads(value)[int(key)]) 86 | 87 | 88 | def extract_item_from_array_to_bool(value, key) -> bool: 89 | """Extract item from array to int.""" 90 | return bool(json.loads(value)[int(key)]) 91 | 92 | 93 | def extract_item_from_json_to_float(value, key) -> float: 94 | """Extract item from json to float.""" 95 | return float(json.loads(value)[str(key)]) 96 | 97 | 98 | def transform_code(value, mapping_table) -> str: 99 | """Transform codes into a human readable string.""" 100 | try: 101 | return getattr(GoEChargerStatusCodes, mapping_table)[int(value)] 102 | except KeyError: 103 | return "Definition missing for code %s" % value 104 | 105 | 106 | SENSORS: tuple[GoEChargerSensorEntityDescription, ...] = ( 107 | GoEChargerSensorEntityDescription( 108 | key="+/result", 109 | name="Last set config key result", 110 | entity_category=None, 111 | device_class=None, 112 | native_unit_of_measurement=None, 113 | state_class=None, 114 | entity_registry_enabled_default=True, 115 | disabled=False, 116 | ), 117 | GoEChargerSensorEntityDescription( 118 | key="ama", 119 | name="Maximum current limit", 120 | entity_category=None, 121 | device_class=SensorDeviceClass.CURRENT, 122 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 123 | state_class=SensorStateClass.MEASUREMENT, 124 | entity_registry_enabled_default=True, 125 | disabled=False, 126 | ), 127 | GoEChargerSensorEntityDescription( 128 | key="ate", 129 | name="Automatic stop energy", 130 | entity_category=None, 131 | device_class=SensorDeviceClass.ENERGY, 132 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 133 | state_class=SensorStateClass.TOTAL_INCREASING, 134 | entity_registry_enabled_default=True, 135 | disabled=False, 136 | ), 137 | GoEChargerSensorEntityDescription( 138 | key="att", 139 | name="Automatic stop time", 140 | entity_category=None, 141 | device_class=None, 142 | native_unit_of_measurement=UnitOfTime.SECONDS, 143 | state_class=SensorStateClass.MEASUREMENT, 144 | icon="mdi:timer-outline", 145 | entity_registry_enabled_default=True, 146 | disabled=False, 147 | ), 148 | GoEChargerSensorEntityDescription( 149 | key="awc", 150 | name="Awattar country", 151 | entity_category=None, 152 | device_class=None, 153 | native_unit_of_measurement=None, 154 | state_class=SensorStateClass.MEASUREMENT, 155 | entity_registry_enabled_default=False, 156 | disabled=True, 157 | disabled_reason="Not exposed via MQTT in firmware 053.1", 158 | ), 159 | GoEChargerSensorEntityDescription( 160 | key="awp", 161 | name="Awattar maximum price threshold", 162 | entity_category=None, 163 | device_class=None, 164 | native_unit_of_measurement=CURRENCY_CENT, 165 | state_class=SensorStateClass.MEASUREMENT, 166 | entity_registry_enabled_default=False, 167 | disabled=False, 168 | ), 169 | GoEChargerSensorEntityDescription( 170 | key="cch", 171 | name="Color charging", 172 | state=remove_quotes, 173 | entity_category=None, 174 | device_class=None, 175 | native_unit_of_measurement=None, 176 | state_class=None, 177 | icon="mdi:format-color-fill", 178 | entity_registry_enabled_default=False, 179 | disabled=False, 180 | ), 181 | GoEChargerSensorEntityDescription( 182 | key="cco", 183 | name="Car consumption", 184 | entity_category=None, 185 | device_class=None, 186 | native_unit_of_measurement=None, 187 | state_class=SensorStateClass.MEASUREMENT, 188 | entity_registry_enabled_default=False, 189 | disabled=True, 190 | disabled_reason="App only", 191 | ), 192 | GoEChargerSensorEntityDescription( 193 | key="cfi", 194 | name="Color finished", 195 | state=remove_quotes, 196 | entity_category=None, 197 | device_class=None, 198 | native_unit_of_measurement=None, 199 | state_class=None, 200 | icon="mdi:format-color-fill", 201 | entity_registry_enabled_default=False, 202 | disabled=False, 203 | ), 204 | GoEChargerSensorEntityDescription( 205 | key="cid", 206 | name="Color idle", 207 | state=remove_quotes, 208 | entity_category=None, 209 | device_class=None, 210 | native_unit_of_measurement=None, 211 | state_class=None, 212 | icon="mdi:format-color-fill", 213 | entity_registry_enabled_default=False, 214 | disabled=False, 215 | ), 216 | GoEChargerSensorEntityDescription( 217 | key="clp", 218 | name="Current limit presets", 219 | entity_category=None, 220 | device_class=None, 221 | native_unit_of_measurement=None, 222 | state_class=None, 223 | entity_registry_enabled_default=False, 224 | disabled=False, 225 | ), 226 | GoEChargerSensorEntityDescription( 227 | key="ct", 228 | name="Car type", 229 | entity_category=None, 230 | device_class=None, 231 | native_unit_of_measurement=None, 232 | state_class=None, 233 | entity_registry_enabled_default=False, 234 | disabled=True, 235 | disabled_reason="App only", 236 | ), 237 | GoEChargerSensorEntityDescription( 238 | key="cwc", 239 | name="Color wait for car", 240 | state=remove_quotes, 241 | entity_category=None, 242 | device_class=None, 243 | native_unit_of_measurement=None, 244 | state_class=None, 245 | icon="mdi:format-color-fill", 246 | entity_registry_enabled_default=False, 247 | disabled=False, 248 | ), 249 | GoEChargerSensorEntityDescription( 250 | key="fna", 251 | name="Friendly name", 252 | entity_category=None, 253 | device_class=None, 254 | native_unit_of_measurement=None, 255 | state_class=SensorStateClass.MEASUREMENT, 256 | entity_registry_enabled_default=False, 257 | disabled=True, 258 | disabled_reason="Not exposed via MQTT in firmware 053.1", 259 | ), 260 | GoEChargerSensorEntityDescription( 261 | key="frc", 262 | name="Force state", 263 | state=transform_code, 264 | attribute="frc", 265 | entity_category=None, 266 | device_class=None, 267 | native_unit_of_measurement=None, 268 | state_class=None, 269 | icon="mdi:auto-fix", 270 | entity_registry_enabled_default=True, 271 | disabled=False, 272 | ), 273 | GoEChargerSensorEntityDescription( 274 | key="frc", 275 | name="Force state code", 276 | entity_category=None, 277 | device_class=None, 278 | native_unit_of_measurement=None, 279 | state_class=None, 280 | icon="mdi:auto-fix", 281 | entity_registry_enabled_default=False, 282 | disabled=False, 283 | ), 284 | GoEChargerSensorEntityDescription( 285 | key="lbr", # 0...255 286 | name="LED brightness", 287 | entity_category=None, 288 | device_class=None, 289 | native_unit_of_measurement=None, 290 | state_class=SensorStateClass.MEASUREMENT, 291 | icon="mdi:brightness-6", 292 | entity_registry_enabled_default=False, 293 | disabled=False, 294 | ), 295 | GoEChargerSensorEntityDescription( 296 | key="lmo", 297 | name="Logic mode", 298 | state=transform_code, 299 | attribute="lmo", 300 | entity_category=None, 301 | device_class=None, 302 | native_unit_of_measurement=None, 303 | state_class=None, 304 | entity_registry_enabled_default=True, 305 | disabled=False, 306 | ), 307 | GoEChargerSensorEntityDescription( 308 | key="lof", 309 | name="Load balancing fallback current", 310 | entity_category=None, 311 | device_class=SensorDeviceClass.CURRENT, 312 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 313 | state_class=SensorStateClass.MEASUREMENT, 314 | entity_registry_enabled_default=False, 315 | disabled=True, 316 | disabled_reason="Not exposed via MQTT in firmware 053.1", 317 | ), 318 | GoEChargerSensorEntityDescription( 319 | key="log", 320 | name="Load balancing group id", 321 | entity_category=None, 322 | device_class=None, 323 | native_unit_of_measurement=None, 324 | state_class=SensorStateClass.MEASUREMENT, 325 | entity_registry_enabled_default=False, 326 | disabled=True, 327 | disabled_reason="Not exposed via MQTT in firmware 053.1", 328 | ), 329 | GoEChargerSensorEntityDescription( 330 | key="lop", 331 | name="Load balancing priority", 332 | entity_category=None, 333 | device_class=None, 334 | native_unit_of_measurement=None, 335 | state_class=SensorStateClass.MEASUREMENT, 336 | entity_registry_enabled_default=False, 337 | disabled=True, 338 | disabled_reason="Not exposed via MQTT in firmware 053.1", 339 | ), 340 | GoEChargerSensorEntityDescription( 341 | key="lot", 342 | name="Load balancing total ampere", 343 | entity_category=None, 344 | device_class=SensorDeviceClass.CURRENT, 345 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 346 | state_class=SensorStateClass.MEASUREMENT, 347 | entity_registry_enabled_default=False, 348 | disabled=True, 349 | disabled_reason="Not exposed via MQTT in firmware 053.1", 350 | ), 351 | GoEChargerSensorEntityDescription( 352 | key="loty", 353 | name="Load balancing type", 354 | entity_category=None, 355 | device_class=None, 356 | native_unit_of_measurement=None, 357 | state_class=SensorStateClass.MEASUREMENT, 358 | entity_registry_enabled_default=False, 359 | disabled=True, 360 | disabled_reason="Not exposed via MQTT in firmware 053.1", 361 | ), 362 | GoEChargerSensorEntityDescription( 363 | key="map", 364 | name="Load mapping", 365 | entity_category=None, 366 | device_class=None, 367 | native_unit_of_measurement=None, 368 | state_class=SensorStateClass.MEASUREMENT, 369 | entity_registry_enabled_default=False, 370 | disabled=True, 371 | disabled_reason="Not exposed via MQTT in firmware 053.1", 372 | ), 373 | GoEChargerSensorEntityDescription( 374 | key="mca", 375 | name="Minimum charging current", 376 | entity_category=None, 377 | device_class=SensorDeviceClass.CURRENT, 378 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 379 | state_class=SensorStateClass.MEASUREMENT, 380 | entity_registry_enabled_default=True, 381 | disabled=False, 382 | ), 383 | GoEChargerSensorEntityDescription( 384 | key="mci", 385 | name="Minimum charging interval", 386 | entity_category=None, 387 | device_class=None, 388 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 389 | state_class=SensorStateClass.MEASUREMENT, 390 | icon="mdi:timer-outline", 391 | entity_registry_enabled_default=False, 392 | disabled=True, 393 | disabled_reason="Not exposed via MQTT in firmware 053.1", 394 | ), 395 | GoEChargerSensorEntityDescription( 396 | key="mcpd", 397 | name="Minimum charge pause duration", 398 | entity_category=None, 399 | device_class=None, 400 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 401 | state_class=SensorStateClass.MEASUREMENT, 402 | icon="mdi:timer-outline", 403 | entity_registry_enabled_default=False, 404 | disabled=True, 405 | disabled_reason="Not exposed via MQTT in firmware 053.1", 406 | ), 407 | GoEChargerSensorEntityDescription( 408 | key="mptwt", 409 | name="Minimum phase toggle wait time", 410 | entity_category=None, 411 | device_class=None, 412 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 413 | state_class=SensorStateClass.MEASUREMENT, 414 | icon="mdi:timer-outline", 415 | entity_registry_enabled_default=False, 416 | disabled=True, 417 | disabled_reason="Not exposed via MQTT in firmware 053.1", 418 | ), 419 | GoEChargerSensorEntityDescription( 420 | key="mpwst", 421 | name="Minimum phase wish switch time", 422 | entity_category=None, 423 | device_class=None, 424 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 425 | state_class=SensorStateClass.MEASUREMENT, 426 | icon="mdi:timer-outline", 427 | entity_registry_enabled_default=False, 428 | disabled=True, 429 | disabled_reason="Not exposed via MQTT in firmware 053.1", 430 | ), 431 | GoEChargerSensorEntityDescription( 432 | key="pass", 433 | name="User password", 434 | entity_category=None, 435 | device_class=None, 436 | native_unit_of_measurement=None, 437 | state_class=SensorStateClass.MEASUREMENT, 438 | entity_registry_enabled_default=False, 439 | disabled=True, 440 | disabled_reason="Not exposed via MQTT in firmware 053.1", 441 | ), 442 | GoEChargerSensorEntityDescription( 443 | key="psmd", 444 | name="Force single phase duration", 445 | entity_category=None, 446 | device_class=None, 447 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 448 | state_class=SensorStateClass.MEASUREMENT, 449 | icon="mdi:timer-outline", 450 | entity_registry_enabled_default=False, 451 | disabled=True, 452 | disabled_reason="Not exposed via MQTT in firmware 053.1", 453 | ), 454 | GoEChargerSensorEntityDescription( 455 | key="sch_satur", 456 | name="Scheduler saturday", 457 | entity_category=None, 458 | device_class=None, 459 | native_unit_of_measurement=None, 460 | state_class=SensorStateClass.MEASUREMENT, 461 | entity_registry_enabled_default=False, 462 | disabled=True, 463 | disabled_reason="Not exposed via MQTT in firmware 053.1", 464 | ), 465 | GoEChargerSensorEntityDescription( 466 | key="sch_sund", 467 | name="Scheduler sunday", 468 | entity_category=None, 469 | device_class=None, 470 | native_unit_of_measurement=None, 471 | state_class=SensorStateClass.MEASUREMENT, 472 | entity_registry_enabled_default=False, 473 | disabled=True, 474 | disabled_reason="Not exposed via MQTT in firmware 053.1", 475 | ), 476 | GoEChargerSensorEntityDescription( 477 | key="sch_week", 478 | name="Scheduler weekday", 479 | entity_category=None, 480 | device_class=None, 481 | native_unit_of_measurement=None, 482 | state_class=SensorStateClass.MEASUREMENT, 483 | entity_registry_enabled_default=False, 484 | disabled=True, 485 | disabled_reason="Not exposed via MQTT in firmware 053.1", 486 | ), 487 | GoEChargerSensorEntityDescription( 488 | key="spl3", 489 | name="Three phase switch level", 490 | entity_category=None, 491 | device_class=SensorDeviceClass.POWER, 492 | native_unit_of_measurement=UnitOfPower.WATT, # This unit is a best guess 493 | state_class=SensorStateClass.MEASUREMENT, 494 | entity_registry_enabled_default=True, 495 | disabled=False, 496 | ), 497 | GoEChargerSensorEntityDescription( 498 | key="sumd", 499 | name="Simulate unplugging duration", 500 | entity_category=None, 501 | device_class=None, 502 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 503 | state_class=SensorStateClass.MEASUREMENT, 504 | icon="mdi:timer-outline", 505 | entity_registry_enabled_default=False, 506 | disabled=True, 507 | disabled_reason="Not exposed via MQTT in firmware 053.1", 508 | ), 509 | GoEChargerSensorEntityDescription( 510 | key="tds", 511 | name="Timezone daylight saving mode", 512 | entity_category=None, 513 | device_class=None, 514 | native_unit_of_measurement=None, 515 | state_class=SensorStateClass.MEASUREMENT, 516 | entity_registry_enabled_default=False, 517 | disabled=True, 518 | disabled_reason="Not exposed via MQTT in firmware 053.1", 519 | ), 520 | GoEChargerSensorEntityDescription( 521 | key="tof", 522 | name="Timezone offset in minutes", 523 | entity_category=None, 524 | device_class=None, 525 | native_unit_of_measurement=None, 526 | state_class=SensorStateClass.MEASUREMENT, 527 | entity_registry_enabled_default=False, 528 | disabled=True, 529 | disabled_reason="Not exposed via MQTT in firmware 053.1", 530 | ), 531 | GoEChargerSensorEntityDescription( 532 | key="ts", 533 | name="Time server", 534 | entity_category=None, 535 | device_class=None, 536 | native_unit_of_measurement=None, 537 | state_class=SensorStateClass.MEASUREMENT, 538 | entity_registry_enabled_default=False, 539 | disabled=True, 540 | disabled_reason="Not exposed via MQTT in firmware 053.1", 541 | ), 542 | GoEChargerSensorEntityDescription( 543 | key="tssi", 544 | name="Time server sync interval", 545 | entity_category=None, 546 | device_class=None, 547 | native_unit_of_measurement=None, 548 | state_class=SensorStateClass.MEASUREMENT, 549 | entity_registry_enabled_default=False, 550 | disabled=True, 551 | disabled_reason="Not exposed via MQTT in firmware 053.1", 552 | ), 553 | GoEChargerSensorEntityDescription( 554 | key="tssm", 555 | name="Time server sync mode", 556 | entity_category=None, 557 | device_class=None, 558 | native_unit_of_measurement=None, 559 | state_class=SensorStateClass.MEASUREMENT, 560 | entity_registry_enabled_default=False, 561 | disabled=True, 562 | disabled_reason="Not exposed via MQTT in firmware 053.1", 563 | ), 564 | GoEChargerSensorEntityDescription( 565 | key="tsss", 566 | name="Time server sync status", 567 | entity_category=None, 568 | device_class=None, 569 | native_unit_of_measurement=None, 570 | state_class=SensorStateClass.MEASUREMENT, 571 | entity_registry_enabled_default=False, 572 | disabled=True, 573 | disabled_reason="Not exposed via MQTT in firmware 053.1", 574 | ), 575 | GoEChargerSensorEntityDescription( 576 | key="ust", 577 | name="Cable unlock mode", 578 | state=transform_code, 579 | attribute="ust", 580 | entity_category=None, 581 | device_class=None, 582 | native_unit_of_measurement=None, 583 | state_class=None, 584 | icon="mdi:account-lock-open", 585 | entity_registry_enabled_default=True, 586 | disabled=False, 587 | ), 588 | GoEChargerSensorEntityDescription( 589 | key="ust", 590 | name="Cable unlock mode code", 591 | entity_category=None, 592 | device_class=None, 593 | native_unit_of_measurement=None, 594 | state_class=None, 595 | icon="mdi:account-lock-open", 596 | entity_registry_enabled_default=False, 597 | disabled=False, 598 | ), 599 | GoEChargerSensorEntityDescription( 600 | key="wak", 601 | name="WiFi accesspoint encryption key", 602 | entity_category=None, 603 | device_class=None, 604 | native_unit_of_measurement=None, 605 | state_class=SensorStateClass.MEASUREMENT, 606 | entity_registry_enabled_default=False, 607 | disabled=True, 608 | disabled_reason="Not exposed via MQTT in firmware 053.1", 609 | ), 610 | GoEChargerSensorEntityDescription( 611 | key="wan", 612 | name="WiFi accesspoint network name", 613 | entity_category=None, 614 | device_class=None, 615 | native_unit_of_measurement=None, 616 | state_class=SensorStateClass.MEASUREMENT, 617 | entity_registry_enabled_default=False, 618 | disabled=True, 619 | disabled_reason="Not exposed via MQTT in firmware 053.1", 620 | ), 621 | GoEChargerSensorEntityDescription( 622 | key="wifis", 623 | name="WiFi configurations", 624 | entity_category=None, 625 | device_class=None, 626 | native_unit_of_measurement=None, 627 | state_class=SensorStateClass.MEASUREMENT, 628 | entity_registry_enabled_default=False, 629 | disabled=True, 630 | disabled_reason="Not exposed via MQTT in firmware 053.1", 631 | ), 632 | GoEChargerSensorEntityDescription( 633 | key="apd", 634 | name="Firmware description", 635 | entity_category=None, 636 | device_class=None, 637 | native_unit_of_measurement=None, 638 | state_class=SensorStateClass.MEASUREMENT, 639 | entity_registry_enabled_default=False, 640 | disabled=True, 641 | disabled_reason="Not exposed via MQTT in firmware 053.1", 642 | ), 643 | GoEChargerSensorEntityDescription( 644 | key="arv", 645 | name="App recommended version", 646 | entity_category=None, 647 | device_class=None, 648 | native_unit_of_measurement=None, 649 | state_class=None, 650 | icon="mdi:numeric", 651 | entity_registry_enabled_default=False, 652 | disabled=True, 653 | disabled_reason="Not exposed via MQTT in firmware 053.1", 654 | ), 655 | GoEChargerSensorEntityDescription( 656 | key="ecf", 657 | name="ESP CPU frequency", 658 | entity_category=None, 659 | device_class=None, 660 | native_unit_of_measurement=None, 661 | state_class=SensorStateClass.MEASUREMENT, 662 | entity_registry_enabled_default=False, 663 | disabled=True, 664 | disabled_reason="Not exposed via MQTT in firmware 053.1", 665 | ), 666 | GoEChargerSensorEntityDescription( 667 | key="eci", 668 | name="ESP Chip info", 669 | entity_category=None, 670 | device_class=None, 671 | native_unit_of_measurement=None, 672 | state_class=SensorStateClass.MEASUREMENT, 673 | entity_registry_enabled_default=False, 674 | disabled=True, 675 | disabled_reason="Not exposed via MQTT in firmware 053.1", 676 | ), 677 | GoEChargerSensorEntityDescription( 678 | key="eem", 679 | name="ESP CPU frequency", 680 | entity_category=None, 681 | device_class=None, 682 | native_unit_of_measurement=None, 683 | state_class=SensorStateClass.MEASUREMENT, 684 | entity_registry_enabled_default=False, 685 | disabled=True, 686 | disabled_reason="Not exposed via MQTT in firmware 053.1", 687 | ), 688 | GoEChargerSensorEntityDescription( 689 | key="efi", 690 | name="ESP Flash info", 691 | entity_category=None, 692 | device_class=None, 693 | native_unit_of_measurement=None, 694 | state_class=SensorStateClass.MEASUREMENT, 695 | entity_registry_enabled_default=False, 696 | disabled=True, 697 | disabled_reason="Not exposed via MQTT in firmware 053.1", 698 | ), 699 | GoEChargerSensorEntityDescription( 700 | key="facwak", 701 | name="WiFi accesspoint key reset value", 702 | entity_category=None, 703 | device_class=None, 704 | native_unit_of_measurement=None, 705 | state_class=SensorStateClass.MEASUREMENT, 706 | entity_registry_enabled_default=False, 707 | disabled=True, 708 | disabled_reason="Not exposed via MQTT in firmware 053.1", 709 | ), 710 | GoEChargerSensorEntityDescription( 711 | key="fem", 712 | name="Flash encryption mode", 713 | entity_category=None, 714 | device_class=None, 715 | native_unit_of_measurement=None, 716 | state_class=SensorStateClass.MEASUREMENT, 717 | entity_registry_enabled_default=False, 718 | disabled=True, 719 | disabled_reason="Not exposed via MQTT in firmware 053.1", 720 | ), 721 | GoEChargerSensorEntityDescription( 722 | key="ffna", 723 | name="Factory friendly name", 724 | entity_category=None, 725 | device_class=None, 726 | native_unit_of_measurement=None, 727 | state_class=SensorStateClass.MEASUREMENT, 728 | entity_registry_enabled_default=False, 729 | disabled=True, 730 | disabled_reason="Not exposed via MQTT in firmware 053.1", 731 | ), 732 | GoEChargerSensorEntityDescription( 733 | key="fwan", 734 | name="Factory WiFi accesspoint network name", 735 | entity_category=None, 736 | device_class=None, 737 | native_unit_of_measurement=None, 738 | state_class=SensorStateClass.MEASUREMENT, 739 | entity_registry_enabled_default=False, 740 | disabled=True, 741 | disabled_reason="Not exposed via MQTT in firmware 053.1", 742 | ), 743 | GoEChargerSensorEntityDescription( 744 | key="fwc", 745 | name="Firmware from car control", 746 | entity_category=None, 747 | device_class=None, 748 | native_unit_of_measurement=None, 749 | state_class=SensorStateClass.MEASUREMENT, 750 | entity_registry_enabled_default=False, 751 | disabled=True, 752 | disabled_reason="Not exposed via MQTT in firmware 053.1", 753 | ), 754 | GoEChargerSensorEntityDescription( 755 | key="fwv", 756 | name="Firmware version", 757 | state=remove_quotes, 758 | entity_category=None, 759 | device_class=None, 760 | native_unit_of_measurement=None, 761 | state_class=None, 762 | icon="mdi:numeric", 763 | entity_registry_enabled_default=False, 764 | disabled=False, 765 | ), 766 | GoEChargerSensorEntityDescription( 767 | key="mod", 768 | name="Hardware version", 769 | entity_category=None, 770 | device_class=None, 771 | native_unit_of_measurement=None, 772 | state_class=None, 773 | icon="mdi:numeric", 774 | entity_registry_enabled_default=False, 775 | disabled=True, 776 | disabled_reason="Not exposed via MQTT in firmware 053.1", 777 | ), 778 | GoEChargerSensorEntityDescription( 779 | key="oem", 780 | name="Manufacturer", 781 | entity_category=None, 782 | device_class=None, 783 | native_unit_of_measurement=None, 784 | state_class=SensorStateClass.MEASUREMENT, 785 | entity_registry_enabled_default=False, 786 | disabled=True, 787 | disabled_reason="Not exposed via MQTT in firmware 053.1", 788 | ), 789 | GoEChargerSensorEntityDescription( 790 | key="otap", 791 | name="Active OTA partition", 792 | entity_category=None, 793 | device_class=None, 794 | native_unit_of_measurement=None, 795 | state_class=SensorStateClass.MEASUREMENT, 796 | entity_registry_enabled_default=False, 797 | disabled=True, 798 | disabled_reason="Not exposed via MQTT in firmware 053.1", 799 | ), 800 | GoEChargerSensorEntityDescription( 801 | key="part", 802 | name="Partition table", 803 | entity_category=None, 804 | device_class=None, 805 | native_unit_of_measurement=None, 806 | state_class=SensorStateClass.MEASUREMENT, 807 | entity_registry_enabled_default=False, 808 | disabled=True, 809 | disabled_reason="Not exposed via MQTT in firmware 053.1", 810 | ), 811 | GoEChargerSensorEntityDescription( 812 | key="pto", 813 | name="Partition table offset in flash", 814 | entity_category=None, 815 | device_class=None, 816 | native_unit_of_measurement=None, 817 | state_class=SensorStateClass.MEASUREMENT, 818 | entity_registry_enabled_default=False, 819 | disabled=True, 820 | disabled_reason="Not exposed via MQTT in firmware 053.1", 821 | ), 822 | GoEChargerSensorEntityDescription( 823 | key="sse", 824 | name="Serial number", 825 | entity_category=None, 826 | device_class=None, 827 | native_unit_of_measurement=None, 828 | state_class=SensorStateClass.MEASUREMENT, 829 | entity_registry_enabled_default=False, 830 | disabled=True, 831 | disabled_reason="Not exposed via MQTT in firmware 053.1", 832 | ), 833 | GoEChargerSensorEntityDescription( 834 | key="typ", 835 | name="Device type", 836 | entity_category=None, 837 | device_class=None, 838 | native_unit_of_measurement=None, 839 | state_class=SensorStateClass.MEASUREMENT, 840 | entity_registry_enabled_default=False, 841 | disabled=True, 842 | disabled_reason="Not exposed via MQTT in firmware 053.1", 843 | ), 844 | GoEChargerSensorEntityDescription( 845 | key="var", 846 | name="Device variant", 847 | entity_category=None, 848 | device_class=SensorDeviceClass.POWER, 849 | native_unit_of_measurement=UnitOfPower.KILO_WATT, 850 | state_class=None, 851 | icon="mdi:image-size-select-large", 852 | entity_registry_enabled_default=False, 853 | disabled=False, 854 | ), 855 | GoEChargerSensorEntityDescription( 856 | key="del", 857 | name="Delete card", 858 | entity_category=None, 859 | device_class=None, 860 | native_unit_of_measurement=None, 861 | state_class=SensorStateClass.MEASUREMENT, 862 | entity_registry_enabled_default=False, 863 | disabled=True, 864 | disabled_reason="Not exposed via MQTT in firmware 053.1", 865 | ), 866 | GoEChargerSensorEntityDescription( 867 | key="delw", 868 | name="Delete STA config", 869 | entity_category=None, 870 | device_class=None, 871 | native_unit_of_measurement=None, 872 | state_class=SensorStateClass.MEASUREMENT, 873 | entity_registry_enabled_default=False, 874 | disabled=True, 875 | disabled_reason="Not exposed via MQTT in firmware 053.1", 876 | ), 877 | GoEChargerSensorEntityDescription( 878 | key="lrn", 879 | name="Learn card", 880 | entity_category=None, 881 | device_class=None, 882 | native_unit_of_measurement=None, 883 | state_class=SensorStateClass.MEASUREMENT, 884 | entity_registry_enabled_default=False, 885 | disabled=True, 886 | disabled_reason="Not exposed via MQTT in firmware 053.1", 887 | ), 888 | GoEChargerSensorEntityDescription( 889 | key="oct", 890 | name="Firmware update trigger", 891 | entity_category=None, 892 | device_class=None, 893 | native_unit_of_measurement=None, 894 | state_class=SensorStateClass.MEASUREMENT, 895 | entity_registry_enabled_default=False, 896 | disabled=True, 897 | disabled_reason="Not exposed via MQTT in firmware 053.1", 898 | ), 899 | GoEChargerSensorEntityDescription( 900 | key="acu", 901 | name="Maximum allowed current", 902 | entity_category=EntityCategory.DIAGNOSTIC, 903 | device_class=SensorDeviceClass.CURRENT, 904 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 905 | state_class=SensorStateClass.MEASUREMENT, 906 | entity_registry_enabled_default=True, 907 | disabled=False, 908 | ), 909 | GoEChargerSensorEntityDescription( 910 | key="amt", 911 | name="Current temperature limit", 912 | entity_category=EntityCategory.DIAGNOSTIC, 913 | device_class=SensorDeviceClass.TEMPERATURE, 914 | native_unit_of_measurement=UnitOfTemperature.CELSIUS, 915 | state_class=SensorStateClass.MEASUREMENT, 916 | entity_registry_enabled_default=True, 917 | disabled=False, 918 | ), 919 | GoEChargerSensorEntityDescription( 920 | key="atp", 921 | name="Next trip plan data", 922 | entity_category=EntityCategory.DIAGNOSTIC, 923 | device_class=None, 924 | native_unit_of_measurement=None, 925 | state_class=SensorStateClass.MEASUREMENT, 926 | entity_registry_enabled_default=False, 927 | disabled=True, 928 | disabled_reason="Not exposed via MQTT in firmware 053.1", 929 | ), 930 | GoEChargerSensorEntityDescription( 931 | key="awcp", 932 | name="Awattar current price", 933 | state=extract_item_from_json_to_float, 934 | attribute="marketprice", 935 | entity_category=EntityCategory.DIAGNOSTIC, 936 | device_class=None, 937 | native_unit_of_measurement=CURRENCY_CENT, 938 | state_class=SensorStateClass.MEASUREMENT, 939 | entity_registry_enabled_default=False, 940 | disabled=False, 941 | ), 942 | GoEChargerSensorEntityDescription( 943 | key="awpl", 944 | name="Awattar price list", 945 | entity_category=EntityCategory.DIAGNOSTIC, 946 | device_class=None, 947 | native_unit_of_measurement=None, 948 | state_class=SensorStateClass.MEASUREMENT, 949 | entity_registry_enabled_default=False, 950 | disabled=True, 951 | disabled_reason="Not exposed via MQTT in firmware 053.1", 952 | ), 953 | GoEChargerSensorEntityDescription( 954 | key="car", 955 | name="Car state", 956 | state=transform_code, 957 | attribute="car", 958 | entity_category=EntityCategory.DIAGNOSTIC, 959 | device_class=None, 960 | native_unit_of_measurement=None, 961 | state_class=None, 962 | icon="mdi:heart-pulse", 963 | entity_registry_enabled_default=True, 964 | disabled=False, 965 | ), 966 | GoEChargerSensorEntityDescription( 967 | key="cbl", 968 | name="Cable maximum current", 969 | entity_category=EntityCategory.DIAGNOSTIC, 970 | device_class=SensorDeviceClass.CURRENT, 971 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 972 | state_class=SensorStateClass.MEASUREMENT, 973 | entity_registry_enabled_default=False, 974 | disabled=False, 975 | ), 976 | GoEChargerSensorEntityDescription( 977 | key="ccu", 978 | name="Charge controller update progress", 979 | entity_category=EntityCategory.DIAGNOSTIC, 980 | device_class=None, 981 | native_unit_of_measurement=None, 982 | state_class=SensorStateClass.MEASUREMENT, 983 | entity_registry_enabled_default=False, 984 | disabled=True, 985 | disabled_reason="Not exposed via MQTT in firmware 053.1", 986 | ), 987 | GoEChargerSensorEntityDescription( 988 | key="ccw", 989 | name="Connected WiFi", 990 | entity_category=EntityCategory.DIAGNOSTIC, 991 | device_class=None, 992 | native_unit_of_measurement=None, 993 | state_class=SensorStateClass.MEASUREMENT, 994 | entity_registry_enabled_default=False, 995 | disabled=True, 996 | disabled_reason="JSON decoding required. Values non-essential", 997 | ), 998 | GoEChargerSensorEntityDescription( 999 | key="cdi", 1000 | name="Charging duration", 1001 | state=extract_charging_duration, 1002 | attribute="1", 1003 | entity_category=EntityCategory.DIAGNOSTIC, 1004 | device_class=None, 1005 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1006 | state_class=SensorStateClass.MEASUREMENT, 1007 | icon="mdi:timer-outline", 1008 | entity_registry_enabled_default=True, 1009 | disabled=False, 1010 | ), 1011 | GoEChargerSensorEntityDescription( 1012 | key="cdi", 1013 | name="Charging duration counter", 1014 | state=extract_charging_duration, 1015 | attribute="0", 1016 | entity_category=EntityCategory.DIAGNOSTIC, 1017 | device_class=None, 1018 | native_unit_of_measurement=None, 1019 | state_class=SensorStateClass.MEASUREMENT, 1020 | icon="mdi:counter", 1021 | entity_registry_enabled_default=False, 1022 | disabled=False, 1023 | ), 1024 | GoEChargerSensorEntityDescription( 1025 | key="cus", 1026 | name="Cable unlock status code", 1027 | entity_category=EntityCategory.DIAGNOSTIC, 1028 | device_class=None, 1029 | native_unit_of_measurement=None, 1030 | state_class=None, 1031 | icon="mdi:shield-lock-open-outline", 1032 | entity_registry_enabled_default=False, 1033 | disabled=False, 1034 | ), 1035 | GoEChargerSensorEntityDescription( 1036 | key="cus", 1037 | name="Cable unlock status", 1038 | state=transform_code, 1039 | attribute="cus", 1040 | entity_category=EntityCategory.DIAGNOSTIC, 1041 | device_class=None, 1042 | native_unit_of_measurement=None, 1043 | state_class=None, 1044 | icon="mdi:shield-lock-open-outline", 1045 | entity_registry_enabled_default=True, 1046 | disabled=False, 1047 | ), 1048 | GoEChargerSensorEntityDescription( 1049 | key="cwsca", 1050 | name="Cloud websocket connected", 1051 | entity_category=EntityCategory.DIAGNOSTIC, 1052 | device_class=None, 1053 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1054 | state_class=SensorStateClass.MEASUREMENT, 1055 | icon="mdi:timer-outline", 1056 | entity_registry_enabled_default=False, 1057 | disabled=True, 1058 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1059 | ), 1060 | GoEChargerSensorEntityDescription( 1061 | key="efh", 1062 | name="ESP free heap", 1063 | entity_category=EntityCategory.DIAGNOSTIC, 1064 | device_class=None, 1065 | native_unit_of_measurement=None, 1066 | state_class=SensorStateClass.MEASUREMENT, 1067 | entity_registry_enabled_default=False, 1068 | disabled=True, 1069 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1070 | ), 1071 | GoEChargerSensorEntityDescription( 1072 | key="efh32", 1073 | name="ESP free heap 32bit aligned", 1074 | entity_category=EntityCategory.DIAGNOSTIC, 1075 | device_class=None, 1076 | native_unit_of_measurement=None, 1077 | state_class=SensorStateClass.MEASUREMENT, 1078 | entity_registry_enabled_default=False, 1079 | disabled=True, 1080 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1081 | ), 1082 | GoEChargerSensorEntityDescription( 1083 | key="efh8", 1084 | name="ESP free heap 8bit aligned", 1085 | entity_category=EntityCategory.DIAGNOSTIC, 1086 | device_class=None, 1087 | native_unit_of_measurement=None, 1088 | state_class=SensorStateClass.MEASUREMENT, 1089 | entity_registry_enabled_default=False, 1090 | disabled=True, 1091 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1092 | ), 1093 | GoEChargerSensorEntityDescription( 1094 | key="ehs", 1095 | name="ESP heap size", 1096 | entity_category=EntityCategory.DIAGNOSTIC, 1097 | device_class=None, 1098 | native_unit_of_measurement=None, 1099 | state_class=SensorStateClass.MEASUREMENT, 1100 | entity_registry_enabled_default=False, 1101 | disabled=True, 1102 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1103 | ), 1104 | GoEChargerSensorEntityDescription( 1105 | key="emfh", 1106 | name="ESP minimum free heap since boot", 1107 | entity_category=EntityCategory.DIAGNOSTIC, 1108 | device_class=None, 1109 | native_unit_of_measurement=None, 1110 | state_class=SensorStateClass.MEASUREMENT, 1111 | entity_registry_enabled_default=False, 1112 | disabled=True, 1113 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1114 | ), 1115 | GoEChargerSensorEntityDescription( 1116 | key="emhb", 1117 | name="ESP maximum size of allocated heap block since boot", 1118 | entity_category=EntityCategory.DIAGNOSTIC, 1119 | device_class=None, 1120 | native_unit_of_measurement=None, 1121 | state_class=SensorStateClass.MEASUREMENT, 1122 | entity_registry_enabled_default=False, 1123 | disabled=True, 1124 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1125 | ), 1126 | GoEChargerSensorEntityDescription( 1127 | key="err", 1128 | name="Error", 1129 | state=transform_code, 1130 | attribute="err", 1131 | entity_category=EntityCategory.DIAGNOSTIC, 1132 | device_class=None, 1133 | native_unit_of_measurement=None, 1134 | state_class=None, 1135 | icon="mdi:alert-circle-outline", 1136 | entity_registry_enabled_default=True, 1137 | disabled=False, 1138 | ), 1139 | GoEChargerSensorEntityDescription( 1140 | key="err", 1141 | name="Error code", 1142 | entity_category=EntityCategory.DIAGNOSTIC, 1143 | device_class=None, 1144 | native_unit_of_measurement=None, 1145 | state_class=None, 1146 | icon="mdi:alert-circle-outline", 1147 | entity_registry_enabled_default=False, 1148 | disabled=False, 1149 | ), 1150 | GoEChargerSensorEntityDescription( 1151 | key="esr", 1152 | name="RTC reset reason", 1153 | entity_category=EntityCategory.DIAGNOSTIC, 1154 | device_class=None, 1155 | native_unit_of_measurement=None, 1156 | state_class=SensorStateClass.MEASUREMENT, 1157 | entity_registry_enabled_default=False, 1158 | disabled=True, 1159 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1160 | ), 1161 | GoEChargerSensorEntityDescription( 1162 | key="eto", 1163 | name="Total energy", 1164 | entity_category=EntityCategory.DIAGNOSTIC, 1165 | device_class=SensorDeviceClass.ENERGY, 1166 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 1167 | state_class=SensorStateClass.TOTAL_INCREASING, 1168 | entity_registry_enabled_default=True, 1169 | disabled=False, 1170 | ), 1171 | GoEChargerSensorEntityDescription( 1172 | key="etop", 1173 | name="Total energy persisted", 1174 | entity_category=EntityCategory.DIAGNOSTIC, 1175 | device_class=SensorDeviceClass.ENERGY, 1176 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 1177 | state_class=SensorStateClass.TOTAL_INCREASING, 1178 | entity_registry_enabled_default=False, 1179 | disabled=True, 1180 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1181 | ), 1182 | GoEChargerSensorEntityDescription( 1183 | key="ffb", 1184 | name="Lock feedback", 1185 | entity_category=EntityCategory.DIAGNOSTIC, 1186 | device_class=None, 1187 | native_unit_of_measurement=None, 1188 | state_class=SensorStateClass.MEASUREMENT, 1189 | entity_registry_enabled_default=False, 1190 | disabled=True, 1191 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1192 | ), 1193 | GoEChargerSensorEntityDescription( 1194 | key="ffba", 1195 | name="Lock feedback age", 1196 | entity_category=EntityCategory.DIAGNOSTIC, 1197 | device_class=None, 1198 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1199 | state_class=SensorStateClass.MEASUREMENT, 1200 | icon="mdi:timer-outline", 1201 | entity_registry_enabled_default=False, 1202 | disabled=True, 1203 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1204 | ), 1205 | GoEChargerSensorEntityDescription( 1206 | key="fhz", 1207 | name="Grid frequency", 1208 | entity_category=EntityCategory.DIAGNOSTIC, 1209 | device_class=None, 1210 | native_unit_of_measurement=UnitOfFrequency.HERTZ, 1211 | state_class=SensorStateClass.MEASUREMENT, 1212 | icon="mdi:current-ac", 1213 | entity_registry_enabled_default=False, 1214 | disabled=False, 1215 | ), 1216 | GoEChargerSensorEntityDescription( 1217 | key="fsptws", 1218 | name="Force single phase toggle wished since", 1219 | entity_category=EntityCategory.DIAGNOSTIC, 1220 | device_class=None, 1221 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1222 | state_class=SensorStateClass.MEASUREMENT, 1223 | icon="mdi:timer-outline", 1224 | entity_registry_enabled_default=False, 1225 | disabled=True, 1226 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1227 | ), 1228 | GoEChargerSensorEntityDescription( 1229 | key="host", 1230 | name="Hostname on STA interface", 1231 | entity_category=EntityCategory.DIAGNOSTIC, 1232 | device_class=None, 1233 | native_unit_of_measurement=None, 1234 | state_class=SensorStateClass.MEASUREMENT, 1235 | entity_registry_enabled_default=False, 1236 | disabled=True, 1237 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1238 | ), 1239 | GoEChargerSensorEntityDescription( 1240 | key="lbp", 1241 | name="Last button press", 1242 | entity_category=EntityCategory.DIAGNOSTIC, 1243 | device_class=None, 1244 | native_unit_of_measurement=None, 1245 | state_class=SensorStateClass.MEASUREMENT, 1246 | entity_registry_enabled_default=False, 1247 | disabled=False, 1248 | ), 1249 | GoEChargerSensorEntityDescription( 1250 | key="lccfc", 1251 | name="Last car state changed from charging", 1252 | entity_category=EntityCategory.DIAGNOSTIC, 1253 | device_class=None, 1254 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1255 | state_class=SensorStateClass.MEASUREMENT, 1256 | icon="mdi:timer-outline", 1257 | entity_registry_enabled_default=True, 1258 | disabled=False, 1259 | ), 1260 | GoEChargerSensorEntityDescription( 1261 | key="lccfi", 1262 | name="Last car state changed from idle", 1263 | entity_category=EntityCategory.DIAGNOSTIC, 1264 | device_class=None, 1265 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1266 | state_class=SensorStateClass.MEASUREMENT, 1267 | icon="mdi:timer-outline", 1268 | entity_registry_enabled_default=True, 1269 | disabled=False, 1270 | ), 1271 | GoEChargerSensorEntityDescription( 1272 | key="lcctc", 1273 | name="Last car state changed to charging", 1274 | entity_category=EntityCategory.DIAGNOSTIC, 1275 | device_class=None, 1276 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1277 | state_class=SensorStateClass.MEASUREMENT, 1278 | icon="mdi:timer-outline", 1279 | entity_registry_enabled_default=True, 1280 | disabled=False, 1281 | ), 1282 | GoEChargerSensorEntityDescription( 1283 | key="lck", 1284 | name="Effective lock setting", 1285 | entity_category=EntityCategory.DIAGNOSTIC, 1286 | device_class=None, 1287 | native_unit_of_measurement=None, 1288 | state_class=SensorStateClass.MEASUREMENT, 1289 | entity_registry_enabled_default=False, 1290 | disabled=True, 1291 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1292 | ), 1293 | GoEChargerSensorEntityDescription( 1294 | key="led", 1295 | name="LED animation details", 1296 | entity_category=EntityCategory.DIAGNOSTIC, 1297 | device_class=None, 1298 | native_unit_of_measurement=None, 1299 | state_class=SensorStateClass.MEASUREMENT, 1300 | entity_registry_enabled_default=False, 1301 | disabled=True, 1302 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1303 | ), 1304 | GoEChargerSensorEntityDescription( 1305 | key="lfspt", 1306 | name="Last force single phase toggle", 1307 | entity_category=EntityCategory.DIAGNOSTIC, 1308 | device_class=None, 1309 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1310 | state_class=SensorStateClass.MEASUREMENT, 1311 | icon="mdi:timer-outline", 1312 | entity_registry_enabled_default=False, 1313 | disabled=True, 1314 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1315 | ), 1316 | GoEChargerSensorEntityDescription( 1317 | key="lmsc", 1318 | name="Last mode change", 1319 | entity_category=EntityCategory.DIAGNOSTIC, 1320 | device_class=None, 1321 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1322 | state_class=SensorStateClass.MEASUREMENT, 1323 | icon="mdi:timer-outline", 1324 | entity_registry_enabled_default=False, 1325 | disabled=False, 1326 | ), 1327 | GoEChargerSensorEntityDescription( 1328 | key="loa", 1329 | name="Load balancing available current", 1330 | entity_category=EntityCategory.DIAGNOSTIC, 1331 | device_class=SensorDeviceClass.CURRENT, 1332 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 1333 | state_class=SensorStateClass.MEASUREMENT, 1334 | entity_registry_enabled_default=True, 1335 | disabled=False, 1336 | ), 1337 | GoEChargerSensorEntityDescription( 1338 | key="loc", 1339 | name="Local time", 1340 | entity_category=EntityCategory.DIAGNOSTIC, 1341 | device_class=None, 1342 | native_unit_of_measurement=None, 1343 | state_class=SensorStateClass.MEASUREMENT, 1344 | entity_registry_enabled_default=False, 1345 | disabled=True, 1346 | disabled_reason="Valueless with a high update interval of 1s", 1347 | ), 1348 | GoEChargerSensorEntityDescription( 1349 | key="lom", 1350 | name="Load balancing members", 1351 | entity_category=EntityCategory.DIAGNOSTIC, 1352 | device_class=None, 1353 | native_unit_of_measurement=None, 1354 | state_class=SensorStateClass.MEASUREMENT, 1355 | entity_registry_enabled_default=False, 1356 | icon="mdi:account-multiple", 1357 | disabled=True, 1358 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1359 | ), 1360 | GoEChargerSensorEntityDescription( 1361 | key="los", 1362 | name="Load balancing status", 1363 | entity_category=EntityCategory.DIAGNOSTIC, 1364 | device_class=None, 1365 | native_unit_of_measurement=None, 1366 | state_class=SensorStateClass.MEASUREMENT, 1367 | entity_registry_enabled_default=False, 1368 | disabled=True, 1369 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1370 | ), 1371 | GoEChargerSensorEntityDescription( 1372 | key="lssfc", 1373 | name="WiFi station disconnected since", 1374 | entity_category=EntityCategory.DIAGNOSTIC, 1375 | device_class=None, 1376 | native_unit_of_measurement=None, 1377 | state_class=SensorStateClass.MEASUREMENT, 1378 | entity_registry_enabled_default=False, 1379 | disabled=True, 1380 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1381 | ), 1382 | GoEChargerSensorEntityDescription( 1383 | key="lsstc", 1384 | name="WiFi station connected since", 1385 | entity_category=EntityCategory.DIAGNOSTIC, 1386 | device_class=None, 1387 | native_unit_of_measurement=None, 1388 | state_class=SensorStateClass.MEASUREMENT, 1389 | entity_registry_enabled_default=False, 1390 | disabled=True, 1391 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1392 | ), 1393 | GoEChargerSensorEntityDescription( 1394 | key="mcpea", 1395 | name="Minimum charge pause ends at", 1396 | entity_category=EntityCategory.DIAGNOSTIC, 1397 | device_class=None, 1398 | native_unit_of_measurement=UnitOfTime.MILLISECONDS, 1399 | state_class=SensorStateClass.MEASUREMENT, 1400 | icon="mdi:timer-outline", 1401 | entity_registry_enabled_default=False, 1402 | disabled=True, 1403 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1404 | ), 1405 | GoEChargerSensorEntityDescription( 1406 | key="mmp", 1407 | name="Maximum measured charging power", 1408 | entity_category=EntityCategory.DIAGNOSTIC, 1409 | device_class=SensorDeviceClass.POWER, 1410 | native_unit_of_measurement=UnitOfPower.WATT, 1411 | state_class=SensorStateClass.MEASUREMENT, 1412 | entity_registry_enabled_default=False, 1413 | disabled=True, 1414 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1415 | ), 1416 | GoEChargerSensorEntityDescription( 1417 | key="modelStatus", 1418 | name="Status", 1419 | state=transform_code, 1420 | attribute="modelStatus", 1421 | entity_category=EntityCategory.DIAGNOSTIC, 1422 | device_class=None, 1423 | native_unit_of_measurement=None, 1424 | state_class=None, 1425 | icon="mdi:heart-pulse", 1426 | entity_registry_enabled_default=True, 1427 | disabled=False, 1428 | ), 1429 | GoEChargerSensorEntityDescription( 1430 | key="modelStatus", 1431 | name="Status code", 1432 | entity_category=EntityCategory.DIAGNOSTIC, 1433 | device_class=None, 1434 | native_unit_of_measurement=None, 1435 | state_class=None, 1436 | icon="mdi:heart-pulse", 1437 | entity_registry_enabled_default=False, 1438 | disabled=False, 1439 | ), 1440 | GoEChargerSensorEntityDescription( 1441 | key="msi", 1442 | name="Reason why we allow charging or not", 1443 | entity_category=EntityCategory.DIAGNOSTIC, 1444 | device_class=None, 1445 | native_unit_of_measurement=None, 1446 | state_class=SensorStateClass.MEASUREMENT, 1447 | entity_registry_enabled_default=False, 1448 | disabled=True, 1449 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1450 | ), 1451 | GoEChargerSensorEntityDescription( 1452 | key="nrg", 1453 | attribute="0", 1454 | name="Voltage L1", 1455 | state=extract_item_from_array_to_float, 1456 | entity_category=EntityCategory.DIAGNOSTIC, 1457 | device_class=SensorDeviceClass.VOLTAGE, 1458 | native_unit_of_measurement=UnitOfElectricPotential.VOLT, 1459 | state_class=SensorStateClass.MEASUREMENT, 1460 | entity_registry_enabled_default=True, 1461 | disabled=False, 1462 | ), 1463 | GoEChargerSensorEntityDescription( 1464 | key="nrg", 1465 | attribute="1", 1466 | name="Voltage L2", 1467 | state=extract_item_from_array_to_float, 1468 | entity_category=EntityCategory.DIAGNOSTIC, 1469 | device_class=SensorDeviceClass.VOLTAGE, 1470 | native_unit_of_measurement=UnitOfElectricPotential.VOLT, 1471 | state_class=SensorStateClass.MEASUREMENT, 1472 | entity_registry_enabled_default=True, 1473 | disabled=False, 1474 | ), 1475 | GoEChargerSensorEntityDescription( 1476 | key="nrg", 1477 | attribute="2", 1478 | name="Voltage L3", 1479 | state=extract_item_from_array_to_float, 1480 | entity_category=EntityCategory.DIAGNOSTIC, 1481 | device_class=SensorDeviceClass.VOLTAGE, 1482 | native_unit_of_measurement=UnitOfElectricPotential.VOLT, 1483 | state_class=SensorStateClass.MEASUREMENT, 1484 | entity_registry_enabled_default=True, 1485 | disabled=False, 1486 | ), 1487 | GoEChargerSensorEntityDescription( 1488 | key="nrg", 1489 | attribute="3", 1490 | name="Voltage N", 1491 | state=extract_item_from_array_to_float, 1492 | entity_category=EntityCategory.DIAGNOSTIC, 1493 | device_class=SensorDeviceClass.VOLTAGE, 1494 | native_unit_of_measurement=UnitOfElectricPotential.VOLT, 1495 | state_class=SensorStateClass.MEASUREMENT, 1496 | entity_registry_enabled_default=True, 1497 | disabled=False, 1498 | ), 1499 | GoEChargerSensorEntityDescription( 1500 | key="nrg", 1501 | attribute="4", 1502 | name="Current L1", 1503 | state=extract_item_from_array_to_float, 1504 | entity_category=EntityCategory.DIAGNOSTIC, 1505 | device_class=SensorDeviceClass.CURRENT, 1506 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 1507 | state_class=SensorStateClass.MEASUREMENT, 1508 | entity_registry_enabled_default=True, 1509 | disabled=False, 1510 | ), 1511 | GoEChargerSensorEntityDescription( 1512 | key="nrg", 1513 | attribute="5", 1514 | name="Current L2", 1515 | state=extract_item_from_array_to_float, 1516 | entity_category=EntityCategory.DIAGNOSTIC, 1517 | device_class=SensorDeviceClass.CURRENT, 1518 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 1519 | state_class=SensorStateClass.MEASUREMENT, 1520 | entity_registry_enabled_default=True, 1521 | disabled=False, 1522 | ), 1523 | GoEChargerSensorEntityDescription( 1524 | key="nrg", 1525 | attribute="6", 1526 | name="Current L3", 1527 | state=extract_item_from_array_to_float, 1528 | entity_category=EntityCategory.DIAGNOSTIC, 1529 | device_class=SensorDeviceClass.CURRENT, 1530 | native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, 1531 | state_class=SensorStateClass.MEASUREMENT, 1532 | entity_registry_enabled_default=True, 1533 | disabled=False, 1534 | ), 1535 | GoEChargerSensorEntityDescription( 1536 | key="nrg", 1537 | attribute="7", 1538 | name="Power L1", 1539 | state=extract_item_from_array_to_float, 1540 | entity_category=EntityCategory.DIAGNOSTIC, 1541 | device_class=SensorDeviceClass.POWER, 1542 | native_unit_of_measurement=UnitOfPower.WATT, 1543 | state_class=SensorStateClass.MEASUREMENT, 1544 | entity_registry_enabled_default=True, 1545 | disabled=False, 1546 | ), 1547 | GoEChargerSensorEntityDescription( 1548 | key="nrg", 1549 | attribute="8", 1550 | name="Power L2", 1551 | state=extract_item_from_array_to_float, 1552 | entity_category=EntityCategory.DIAGNOSTIC, 1553 | device_class=SensorDeviceClass.POWER, 1554 | native_unit_of_measurement=UnitOfPower.WATT, 1555 | state_class=SensorStateClass.MEASUREMENT, 1556 | entity_registry_enabled_default=True, 1557 | disabled=False, 1558 | ), 1559 | GoEChargerSensorEntityDescription( 1560 | key="nrg", 1561 | attribute="9", 1562 | name="Power L3", 1563 | state=extract_item_from_array_to_float, 1564 | entity_category=EntityCategory.DIAGNOSTIC, 1565 | device_class=SensorDeviceClass.POWER, 1566 | native_unit_of_measurement=UnitOfPower.WATT, 1567 | state_class=SensorStateClass.MEASUREMENT, 1568 | entity_registry_enabled_default=True, 1569 | disabled=False, 1570 | ), 1571 | GoEChargerSensorEntityDescription( 1572 | key="nrg", 1573 | attribute="10", 1574 | name="Power N", 1575 | state=extract_item_from_array_to_float, 1576 | entity_category=EntityCategory.DIAGNOSTIC, 1577 | device_class=SensorDeviceClass.POWER, 1578 | native_unit_of_measurement=UnitOfPower.WATT, 1579 | state_class=SensorStateClass.MEASUREMENT, 1580 | entity_registry_enabled_default=True, 1581 | disabled=False, 1582 | ), 1583 | GoEChargerSensorEntityDescription( 1584 | key="nrg", 1585 | attribute="11", 1586 | name="Current power", 1587 | state=extract_item_from_array_to_float, 1588 | entity_category=EntityCategory.DIAGNOSTIC, 1589 | device_class=SensorDeviceClass.POWER, 1590 | native_unit_of_measurement=UnitOfPower.WATT, 1591 | state_class=SensorStateClass.MEASUREMENT, 1592 | entity_registry_enabled_default=True, 1593 | disabled=False, 1594 | ), 1595 | GoEChargerSensorEntityDescription( 1596 | key="nrg", 1597 | attribute="12", 1598 | name="Power factor L1", 1599 | state=extract_item_from_array_to_float, 1600 | entity_category=EntityCategory.DIAGNOSTIC, 1601 | device_class=SensorDeviceClass.POWER_FACTOR, 1602 | native_unit_of_measurement=PERCENTAGE, 1603 | state_class=SensorStateClass.MEASUREMENT, 1604 | entity_registry_enabled_default=True, 1605 | disabled=False, 1606 | ), 1607 | GoEChargerSensorEntityDescription( 1608 | key="nrg", 1609 | attribute="13", 1610 | name="Power factor L2", 1611 | state=extract_item_from_array_to_float, 1612 | entity_category=EntityCategory.DIAGNOSTIC, 1613 | device_class=SensorDeviceClass.POWER_FACTOR, 1614 | native_unit_of_measurement=PERCENTAGE, 1615 | state_class=SensorStateClass.MEASUREMENT, 1616 | entity_registry_enabled_default=True, 1617 | disabled=False, 1618 | ), 1619 | GoEChargerSensorEntityDescription( 1620 | key="nrg", 1621 | attribute="14", 1622 | name="Power factor L3", 1623 | state=extract_item_from_array_to_float, 1624 | entity_category=EntityCategory.DIAGNOSTIC, 1625 | device_class=SensorDeviceClass.POWER_FACTOR, 1626 | native_unit_of_measurement=PERCENTAGE, 1627 | state_class=SensorStateClass.MEASUREMENT, 1628 | entity_registry_enabled_default=True, 1629 | disabled=False, 1630 | ), 1631 | GoEChargerSensorEntityDescription( 1632 | key="nrg", 1633 | attribute="15", 1634 | name="Power factor N", 1635 | state=extract_item_from_array_to_float, 1636 | entity_category=EntityCategory.DIAGNOSTIC, 1637 | device_class=SensorDeviceClass.POWER_FACTOR, 1638 | native_unit_of_measurement=PERCENTAGE, 1639 | state_class=SensorStateClass.MEASUREMENT, 1640 | entity_registry_enabled_default=True, 1641 | disabled=False, 1642 | ), 1643 | GoEChargerSensorEntityDescription( 1644 | key="oca", 1645 | name="OTA cloud app description", 1646 | entity_category=EntityCategory.DIAGNOSTIC, 1647 | device_class=None, 1648 | native_unit_of_measurement=None, 1649 | state_class=SensorStateClass.MEASUREMENT, 1650 | entity_registry_enabled_default=False, 1651 | disabled=True, 1652 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1653 | ), 1654 | GoEChargerSensorEntityDescription( 1655 | key="ocl", 1656 | name="OTA from cloud length", 1657 | entity_category=EntityCategory.DIAGNOSTIC, 1658 | device_class=None, 1659 | native_unit_of_measurement=None, 1660 | state_class=SensorStateClass.MEASUREMENT, 1661 | entity_registry_enabled_default=False, 1662 | disabled=True, 1663 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1664 | ), 1665 | GoEChargerSensorEntityDescription( 1666 | key="ocm", 1667 | name="OTA from cloud message", 1668 | entity_category=EntityCategory.DIAGNOSTIC, 1669 | device_class=None, 1670 | native_unit_of_measurement=None, 1671 | state_class=SensorStateClass.MEASUREMENT, 1672 | entity_registry_enabled_default=False, 1673 | disabled=True, 1674 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1675 | ), 1676 | GoEChargerSensorEntityDescription( 1677 | key="ocp", 1678 | name="OTA from cloud progress", 1679 | entity_category=EntityCategory.DIAGNOSTIC, 1680 | device_class=None, 1681 | native_unit_of_measurement=None, 1682 | state_class=SensorStateClass.MEASUREMENT, 1683 | entity_registry_enabled_default=False, 1684 | disabled=True, 1685 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1686 | ), 1687 | GoEChargerSensorEntityDescription( 1688 | key="ocs", 1689 | name="OTA from cloud status", 1690 | entity_category=EntityCategory.DIAGNOSTIC, 1691 | device_class=None, 1692 | native_unit_of_measurement=None, 1693 | state_class=SensorStateClass.MEASUREMENT, 1694 | entity_registry_enabled_default=False, 1695 | disabled=True, 1696 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1697 | ), 1698 | GoEChargerSensorEntityDescription( 1699 | key="ocu", 1700 | name="List of available firmware versions", 1701 | state=json_array_to_csv, 1702 | entity_category=EntityCategory.DIAGNOSTIC, 1703 | device_class=None, 1704 | native_unit_of_measurement=None, 1705 | state_class=None, 1706 | icon="mdi:numeric", 1707 | entity_registry_enabled_default=False, 1708 | disabled=False, 1709 | ), 1710 | GoEChargerSensorEntityDescription( 1711 | key="onv", 1712 | name="Newest OTA version", 1713 | entity_category=EntityCategory.DIAGNOSTIC, 1714 | device_class=None, 1715 | native_unit_of_measurement=None, 1716 | state_class=None, 1717 | icon="mdi:numeric", 1718 | entity_registry_enabled_default=False, 1719 | disabled=True, 1720 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1721 | ), 1722 | GoEChargerSensorEntityDescription( 1723 | key="pwm", 1724 | name="Phase wish mode for debugging", 1725 | entity_category=EntityCategory.DIAGNOSTIC, 1726 | device_class=None, 1727 | native_unit_of_measurement=None, 1728 | state_class=SensorStateClass.MEASUREMENT, 1729 | entity_registry_enabled_default=False, 1730 | disabled=True, 1731 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1732 | ), 1733 | GoEChargerSensorEntityDescription( 1734 | key="qsc", 1735 | name="Queue size cloud", 1736 | entity_category=EntityCategory.DIAGNOSTIC, 1737 | device_class=None, 1738 | native_unit_of_measurement=None, 1739 | state_class=SensorStateClass.MEASUREMENT, 1740 | entity_registry_enabled_default=False, 1741 | disabled=True, 1742 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1743 | ), 1744 | GoEChargerSensorEntityDescription( 1745 | key="qsw", 1746 | name="Queue size web", 1747 | entity_category=EntityCategory.DIAGNOSTIC, 1748 | device_class=None, 1749 | native_unit_of_measurement=None, 1750 | state_class=SensorStateClass.MEASUREMENT, 1751 | entity_registry_enabled_default=False, 1752 | disabled=True, 1753 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1754 | ), 1755 | GoEChargerSensorEntityDescription( 1756 | key="rbc", 1757 | name="Reboot counter", 1758 | entity_category=EntityCategory.DIAGNOSTIC, 1759 | device_class=None, 1760 | native_unit_of_measurement=None, 1761 | state_class=SensorStateClass.TOTAL_INCREASING, 1762 | icon="mdi:counter", 1763 | entity_registry_enabled_default=True, 1764 | disabled=False, 1765 | ), 1766 | GoEChargerSensorEntityDescription( 1767 | key="rbt", 1768 | name="Uptime", 1769 | entity_category=EntityCategory.DIAGNOSTIC, 1770 | device_class=None, 1771 | native_unit_of_measurement=None, 1772 | state_class=SensorStateClass.MEASUREMENT, 1773 | entity_registry_enabled_default=False, 1774 | disabled=True, 1775 | disabled_reason="TODO: Convert to a timestamp first", 1776 | ), 1777 | GoEChargerSensorEntityDescription( 1778 | key="rcd", 1779 | name="Residual current detection", 1780 | entity_category=EntityCategory.DIAGNOSTIC, 1781 | device_class=None, 1782 | native_unit_of_measurement=None, 1783 | state_class=SensorStateClass.MEASUREMENT, 1784 | entity_registry_enabled_default=False, 1785 | disabled=True, 1786 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1787 | ), 1788 | GoEChargerSensorEntityDescription( 1789 | key="rfb", 1790 | name="Relay feedback", 1791 | entity_category=EntityCategory.DIAGNOSTIC, 1792 | device_class=None, 1793 | native_unit_of_measurement=None, 1794 | state_class=SensorStateClass.MEASUREMENT, 1795 | entity_registry_enabled_default=False, 1796 | disabled=True, 1797 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1798 | ), 1799 | GoEChargerSensorEntityDescription( 1800 | key="rr", 1801 | name="ESP reset reason", 1802 | entity_category=EntityCategory.DIAGNOSTIC, 1803 | device_class=None, 1804 | native_unit_of_measurement=None, 1805 | state_class=SensorStateClass.MEASUREMENT, 1806 | entity_registry_enabled_default=False, 1807 | disabled=True, 1808 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1809 | ), 1810 | GoEChargerSensorEntityDescription( 1811 | key="rssi", 1812 | name="WiFi signal strength", 1813 | entity_category=EntityCategory.DIAGNOSTIC, 1814 | device_class=SensorDeviceClass.SIGNAL_STRENGTH, 1815 | native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS, 1816 | state_class=SensorStateClass.MEASUREMENT, 1817 | entity_registry_enabled_default=False, 1818 | disabled=False, 1819 | ), 1820 | GoEChargerSensorEntityDescription( 1821 | key="scaa", 1822 | name="WiFi scan age", 1823 | entity_category=EntityCategory.DIAGNOSTIC, 1824 | device_class=None, 1825 | native_unit_of_measurement=None, 1826 | state_class=SensorStateClass.MEASUREMENT, 1827 | entity_registry_enabled_default=False, 1828 | disabled=True, 1829 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1830 | ), 1831 | GoEChargerSensorEntityDescription( 1832 | key="scan", 1833 | name="WiFi scan result", 1834 | entity_category=EntityCategory.DIAGNOSTIC, 1835 | device_class=None, 1836 | native_unit_of_measurement=None, 1837 | state_class=SensorStateClass.MEASUREMENT, 1838 | entity_registry_enabled_default=False, 1839 | disabled=True, 1840 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1841 | ), 1842 | GoEChargerSensorEntityDescription( 1843 | key="scas", 1844 | name="WiFi scan status", 1845 | entity_category=EntityCategory.DIAGNOSTIC, 1846 | device_class=None, 1847 | native_unit_of_measurement=None, 1848 | state_class=SensorStateClass.MEASUREMENT, 1849 | entity_registry_enabled_default=False, 1850 | disabled=True, 1851 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1852 | ), 1853 | GoEChargerSensorEntityDescription( 1854 | key="tma", 1855 | name="Temperature sensor 1", 1856 | state=extract_item_from_array_to_float, 1857 | entity_category=EntityCategory.DIAGNOSTIC, 1858 | device_class=SensorDeviceClass.TEMPERATURE, 1859 | native_unit_of_measurement=UnitOfTemperature.CELSIUS, 1860 | state_class=SensorStateClass.MEASUREMENT, 1861 | attribute="0", 1862 | entity_registry_enabled_default=True, 1863 | disabled=False, 1864 | ), 1865 | GoEChargerSensorEntityDescription( 1866 | key="tma", 1867 | name="Temperature sensor 2", 1868 | state=extract_item_from_array_to_float, 1869 | entity_category=EntityCategory.DIAGNOSTIC, 1870 | device_class=SensorDeviceClass.TEMPERATURE, 1871 | native_unit_of_measurement=UnitOfTemperature.CELSIUS, 1872 | state_class=SensorStateClass.MEASUREMENT, 1873 | attribute="1", 1874 | entity_registry_enabled_default=True, 1875 | disabled=False, 1876 | ), 1877 | GoEChargerSensorEntityDescription( 1878 | key="tpa", 1879 | name="Total power average", 1880 | entity_category=EntityCategory.DIAGNOSTIC, 1881 | device_class=SensorDeviceClass.POWER, 1882 | native_unit_of_measurement=UnitOfPower.WATT, 1883 | state_class=SensorStateClass.MEASUREMENT, 1884 | entity_registry_enabled_default=True, 1885 | disabled=False, 1886 | ), 1887 | GoEChargerSensorEntityDescription( 1888 | key="trx", 1889 | name="Transaction", 1890 | entity_category=EntityCategory.DIAGNOSTIC, 1891 | device_class=None, 1892 | native_unit_of_measurement=None, 1893 | state_class=SensorStateClass.MEASUREMENT, 1894 | icon="mdi:message-text-lock-outline", 1895 | entity_registry_enabled_default=True, 1896 | disabled=False, 1897 | ), 1898 | GoEChargerSensorEntityDescription( 1899 | key="tsom", 1900 | name="Time server operating mode", 1901 | entity_category=EntityCategory.DIAGNOSTIC, 1902 | device_class=None, 1903 | native_unit_of_measurement=None, 1904 | state_class=SensorStateClass.MEASUREMENT, 1905 | entity_registry_enabled_default=False, 1906 | disabled=True, 1907 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1908 | ), 1909 | GoEChargerSensorEntityDescription( 1910 | key="utc", 1911 | name="UTC time", 1912 | entity_category=EntityCategory.DIAGNOSTIC, 1913 | device_class=None, 1914 | native_unit_of_measurement=None, 1915 | state_class=SensorStateClass.MEASUREMENT, 1916 | entity_registry_enabled_default=False, 1917 | disabled=True, 1918 | disabled_reason="Valueless with a high update interval of 1s", 1919 | ), 1920 | GoEChargerSensorEntityDescription( 1921 | key="wcch", 1922 | name="Clients via http", 1923 | entity_category=EntityCategory.DIAGNOSTIC, 1924 | device_class=None, 1925 | native_unit_of_measurement=None, 1926 | state_class=SensorStateClass.MEASUREMENT, 1927 | entity_registry_enabled_default=False, 1928 | disabled=True, 1929 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1930 | ), 1931 | GoEChargerSensorEntityDescription( 1932 | key="wccw", 1933 | name="Clients via websocket", 1934 | entity_category=EntityCategory.DIAGNOSTIC, 1935 | device_class=None, 1936 | native_unit_of_measurement=None, 1937 | state_class=SensorStateClass.MEASUREMENT, 1938 | entity_registry_enabled_default=False, 1939 | disabled=True, 1940 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1941 | ), 1942 | GoEChargerSensorEntityDescription( 1943 | key="wh", 1944 | name="Charged energy", 1945 | entity_category=EntityCategory.DIAGNOSTIC, 1946 | device_class=SensorDeviceClass.ENERGY, 1947 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 1948 | state_class=SensorStateClass.TOTAL_INCREASING, 1949 | entity_registry_enabled_default=True, 1950 | disabled=False, 1951 | ), 1952 | GoEChargerSensorEntityDescription( 1953 | key="wsms", 1954 | name="WiFi state machine state", 1955 | entity_category=EntityCategory.DIAGNOSTIC, 1956 | device_class=None, 1957 | native_unit_of_measurement=None, 1958 | state_class=SensorStateClass.MEASUREMENT, 1959 | entity_registry_enabled_default=False, 1960 | disabled=True, 1961 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1962 | ), 1963 | GoEChargerSensorEntityDescription( 1964 | key="wst", # 3: connect, 0: not connected 1965 | name="WiFi station status", 1966 | entity_category=EntityCategory.DIAGNOSTIC, 1967 | device_class=None, 1968 | native_unit_of_measurement=None, 1969 | state_class=SensorStateClass.MEASUREMENT, 1970 | entity_registry_enabled_default=False, 1971 | disabled=True, 1972 | disabled_reason="Not exposed via MQTT in firmware 053.1", 1973 | ), 1974 | GoEChargerSensorEntityDescription( 1975 | key="psm", 1976 | name="Phase switch mode", 1977 | entity_category=None, 1978 | icon="mdi:speedometer", 1979 | device_class=None, 1980 | native_unit_of_measurement=None, 1981 | state_class=None, 1982 | entity_registry_enabled_default=True, 1983 | disabled=False, 1984 | ), 1985 | GoEChargerSensorEntityDescription( 1986 | key="cards", 1987 | name="Charged energy card 1", 1988 | state=extract_energy_from_cards, 1989 | attribute="0", 1990 | entity_category=EntityCategory.DIAGNOSTIC, 1991 | device_class=SensorDeviceClass.ENERGY, 1992 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 1993 | state_class=SensorStateClass.TOTAL_INCREASING, 1994 | entity_registry_enabled_default=True, 1995 | disabled=False, 1996 | ), 1997 | GoEChargerSensorEntityDescription( 1998 | key="cards", 1999 | name="Charged energy card 2", 2000 | state=extract_energy_from_cards, 2001 | attribute="1", 2002 | entity_category=EntityCategory.DIAGNOSTIC, 2003 | device_class=SensorDeviceClass.ENERGY, 2004 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2005 | state_class=SensorStateClass.TOTAL_INCREASING, 2006 | entity_registry_enabled_default=False, 2007 | disabled=False, 2008 | ), 2009 | GoEChargerSensorEntityDescription( 2010 | key="cards", 2011 | name="Charged energy card 3", 2012 | state=extract_energy_from_cards, 2013 | attribute="2", 2014 | entity_category=EntityCategory.DIAGNOSTIC, 2015 | device_class=SensorDeviceClass.ENERGY, 2016 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2017 | state_class=SensorStateClass.TOTAL_INCREASING, 2018 | entity_registry_enabled_default=False, 2019 | disabled=False, 2020 | ), 2021 | GoEChargerSensorEntityDescription( 2022 | key="cards", 2023 | name="Charged energy card 4", 2024 | state=extract_energy_from_cards, 2025 | attribute="3", 2026 | entity_category=EntityCategory.DIAGNOSTIC, 2027 | device_class=SensorDeviceClass.ENERGY, 2028 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2029 | state_class=SensorStateClass.TOTAL_INCREASING, 2030 | entity_registry_enabled_default=False, 2031 | disabled=False, 2032 | ), 2033 | GoEChargerSensorEntityDescription( 2034 | key="cards", 2035 | name="Charged energy card 5", 2036 | state=extract_energy_from_cards, 2037 | attribute="4", 2038 | entity_category=EntityCategory.DIAGNOSTIC, 2039 | device_class=SensorDeviceClass.ENERGY, 2040 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2041 | state_class=SensorStateClass.TOTAL_INCREASING, 2042 | entity_registry_enabled_default=False, 2043 | disabled=False, 2044 | ), 2045 | GoEChargerSensorEntityDescription( 2046 | key="cards", 2047 | name="Charged energy card 6", 2048 | state=extract_energy_from_cards, 2049 | attribute="5", 2050 | entity_category=EntityCategory.DIAGNOSTIC, 2051 | device_class=SensorDeviceClass.ENERGY, 2052 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2053 | state_class=SensorStateClass.TOTAL_INCREASING, 2054 | entity_registry_enabled_default=False, 2055 | disabled=False, 2056 | ), 2057 | GoEChargerSensorEntityDescription( 2058 | key="cards", 2059 | name="Charged energy card 7", 2060 | state=extract_energy_from_cards, 2061 | attribute="6", 2062 | entity_category=EntityCategory.DIAGNOSTIC, 2063 | device_class=SensorDeviceClass.ENERGY, 2064 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2065 | state_class=SensorStateClass.TOTAL_INCREASING, 2066 | entity_registry_enabled_default=False, 2067 | disabled=False, 2068 | ), 2069 | GoEChargerSensorEntityDescription( 2070 | key="cards", 2071 | name="Charged energy card 8", 2072 | state=extract_energy_from_cards, 2073 | attribute="7", 2074 | entity_category=EntityCategory.DIAGNOSTIC, 2075 | device_class=SensorDeviceClass.ENERGY, 2076 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2077 | state_class=SensorStateClass.TOTAL_INCREASING, 2078 | entity_registry_enabled_default=False, 2079 | disabled=False, 2080 | ), 2081 | GoEChargerSensorEntityDescription( 2082 | key="cards", 2083 | name="Charged energy card 9", 2084 | state=extract_energy_from_cards, 2085 | attribute="8", 2086 | entity_category=EntityCategory.DIAGNOSTIC, 2087 | device_class=SensorDeviceClass.ENERGY, 2088 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2089 | state_class=SensorStateClass.TOTAL_INCREASING, 2090 | entity_registry_enabled_default=False, 2091 | disabled=False, 2092 | ), 2093 | GoEChargerSensorEntityDescription( 2094 | key="cards", 2095 | name="Charged energy card 10", 2096 | state=extract_energy_from_cards, 2097 | attribute="9", 2098 | entity_category=EntityCategory.DIAGNOSTIC, 2099 | device_class=SensorDeviceClass.ENERGY, 2100 | native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, 2101 | state_class=SensorStateClass.TOTAL_INCREASING, 2102 | entity_registry_enabled_default=False, 2103 | disabled=False, 2104 | ), 2105 | GoEChargerSensorEntityDescription( 2106 | key="ppv", 2107 | name="Power from Solar Panels (from ids)", 2108 | entity_category=None, 2109 | device_class=SensorDeviceClass.POWER, 2110 | native_unit_of_measurement=UnitOfPower.WATT, 2111 | state_class=SensorStateClass.MEASUREMENT, 2112 | entity_registry_enabled_default=True, 2113 | disabled=False, 2114 | ), 2115 | GoEChargerSensorEntityDescription( 2116 | key="pgrid", 2117 | name="Power from grid (from ids)", 2118 | entity_category=None, 2119 | device_class=SensorDeviceClass.POWER, 2120 | native_unit_of_measurement=UnitOfPower.WATT, 2121 | state_class=SensorStateClass.MEASUREMENT, 2122 | entity_registry_enabled_default=True, 2123 | disabled=False, 2124 | ), 2125 | GoEChargerSensorEntityDescription( 2126 | key="pakku", 2127 | name="Power from battery (from ids)", 2128 | entity_category=None, 2129 | device_class=SensorDeviceClass.POWER, 2130 | native_unit_of_measurement=UnitOfPower.WATT, 2131 | state_class=SensorStateClass.MEASUREMENT, 2132 | entity_registry_enabled_default=True, 2133 | disabled=False, 2134 | ), 2135 | ) 2136 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/definitions/switch.py: -------------------------------------------------------------------------------- 1 | """Definitions for go-eCharger switches exposed via MQTT.""" 2 | from __future__ import annotations 3 | 4 | from dataclasses import dataclass 5 | import logging 6 | 7 | from homeassistant.components.switch import SwitchEntityDescription 8 | from homeassistant.helpers.entity import EntityCategory 9 | 10 | from . import GoEChargerEntityDescription 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | @dataclass 16 | class GoEChargerSwitchEntityDescription( 17 | GoEChargerEntityDescription, SwitchEntityDescription 18 | ): 19 | """Switch entity description for go-eCharger.""" 20 | 21 | domain: str = "switch" 22 | payload_on: str = "true" 23 | payload_off: str = "false" 24 | optimistic: bool = False 25 | 26 | 27 | SWITCHES: tuple[GoEChargerSwitchEntityDescription, ...] = ( 28 | GoEChargerSwitchEntityDescription( 29 | key="bac", 30 | name="Allow current change by button", 31 | entity_category=EntityCategory.CONFIG, 32 | device_class=None, 33 | entity_registry_enabled_default=True, 34 | disabled=False, 35 | ), 36 | GoEChargerSwitchEntityDescription( 37 | key="ara", 38 | name="Automatic stop mode", 39 | entity_category=EntityCategory.CONFIG, 40 | device_class=None, 41 | entity_registry_enabled_default=True, 42 | disabled=False, 43 | ), 44 | GoEChargerSwitchEntityDescription( 45 | key="wen", 46 | name="WiFi enabled", 47 | entity_category=EntityCategory.CONFIG, 48 | device_class=None, 49 | entity_registry_enabled_default=False, 50 | disabled=True, 51 | disabled_reason="Not exposed via MQTT in firmware 053.1", 52 | ), 53 | GoEChargerSwitchEntityDescription( 54 | key="tse", 55 | name="Time server enabled", 56 | entity_category=EntityCategory.CONFIG, 57 | device_class=None, 58 | entity_registry_enabled_default=False, 59 | disabled=True, 60 | disabled_reason="Not exposed via MQTT in firmware 053.1", 61 | ), 62 | GoEChargerSwitchEntityDescription( 63 | key="sdp", 64 | name="Button allow force change", 65 | entity_category=EntityCategory.CONFIG, 66 | device_class=None, 67 | entity_registry_enabled_default=False, 68 | disabled=True, 69 | disabled_reason="Not exposed via MQTT in firmware 053.1", 70 | ), 71 | GoEChargerSwitchEntityDescription( 72 | key="nmo", 73 | name="Norway mode", 74 | entity_category=EntityCategory.CONFIG, 75 | device_class=None, 76 | entity_registry_enabled_default=False, 77 | disabled=True, 78 | disabled_reason="Not exposed via MQTT in firmware 053.1", 79 | ), 80 | GoEChargerSwitchEntityDescription( 81 | key="lse", 82 | name="LED off on standby", 83 | entity_category=EntityCategory.CONFIG, 84 | device_class=None, 85 | entity_registry_enabled_default=False, 86 | disabled=True, 87 | disabled_reason="Not exposed via MQTT in firmware 053.1", 88 | ), 89 | GoEChargerSwitchEntityDescription( 90 | key="awe", 91 | name="Awattar mode", 92 | entity_category=EntityCategory.CONFIG, 93 | device_class=None, 94 | entity_registry_enabled_default=True, 95 | disabled=False, 96 | ), 97 | GoEChargerSwitchEntityDescription( 98 | key="acp", 99 | name="Allow charge pause", 100 | entity_category=EntityCategory.CONFIG, 101 | device_class=None, 102 | entity_registry_enabled_default=True, 103 | disabled=True, 104 | disabled_reason="Not exposed via MQTT in firmware 053.1", 105 | ), 106 | GoEChargerSwitchEntityDescription( 107 | key="esk", 108 | name="Energy set", 109 | entity_category=EntityCategory.CONFIG, 110 | device_class=None, 111 | entity_registry_enabled_default=False, 112 | disabled=True, 113 | disabled_reason="App only", 114 | ), 115 | GoEChargerSwitchEntityDescription( 116 | key="fup", 117 | name="Use PV surplus", 118 | entity_category=EntityCategory.CONFIG, 119 | device_class=None, 120 | entity_registry_enabled_default=True, 121 | icon="mdi:solar-power", 122 | disabled=False, 123 | ), 124 | GoEChargerSwitchEntityDescription( 125 | key="su", 126 | name="Simulate unplugging", 127 | entity_category=EntityCategory.CONFIG, 128 | device_class=None, 129 | entity_registry_enabled_default=False, 130 | disabled=True, 131 | disabled_reason="Not exposed via MQTT in firmware 053.1", 132 | ), 133 | GoEChargerSwitchEntityDescription( 134 | key="hws", 135 | name="HTTP STA reachable", 136 | entity_category=EntityCategory.CONFIG, 137 | device_class=None, 138 | entity_registry_enabled_default=False, 139 | disabled=True, 140 | disabled_reason="Not exposed via MQTT in firmware 053.1", 141 | ), 142 | GoEChargerSwitchEntityDescription( 143 | key="hsa", 144 | name="HTTP STA authentication", 145 | entity_category=EntityCategory.CONFIG, 146 | device_class=None, 147 | entity_registry_enabled_default=False, 148 | disabled=True, 149 | disabled_reason="Not exposed via MQTT in firmware 053.1", 150 | ), 151 | GoEChargerSwitchEntityDescription( 152 | key="loe", 153 | name="Load balancing enabled", 154 | entity_category=EntityCategory.CONFIG, 155 | device_class=None, 156 | entity_registry_enabled_default=False, 157 | icon="mdi:seesaw", 158 | disabled=True, 159 | disabled_reason="Not exposed via MQTT in firmware 053.1", 160 | ), 161 | GoEChargerSwitchEntityDescription( 162 | key="upo", 163 | name="Unlock power outage", 164 | entity_category=EntityCategory.CONFIG, 165 | device_class=None, 166 | entity_registry_enabled_default=False, 167 | disabled=True, 168 | disabled_reason="Not exposed via MQTT in firmware 053.1", 169 | ), 170 | GoEChargerSwitchEntityDescription( 171 | key="cwe", 172 | name="Cloud websocket enabled", 173 | entity_category=EntityCategory.CONFIG, 174 | device_class=None, 175 | entity_registry_enabled_default=False, 176 | disabled=True, 177 | disabled_reason="Not exposed via MQTT in firmware 053.1", 178 | ), 179 | GoEChargerSwitchEntityDescription( 180 | key="sua", 181 | name="Simulate unplugging permanently", 182 | optimistic=True, 183 | entity_category=EntityCategory.CONFIG, 184 | device_class=None, 185 | entity_registry_enabled_default=True, 186 | disabled=False, 187 | ), 188 | GoEChargerSwitchEntityDescription( 189 | key="acs", 190 | name="Card authorization required", 191 | payload_on="1", 192 | payload_off="0", 193 | entity_category=EntityCategory.CONFIG, 194 | device_class=None, 195 | entity_registry_enabled_default=True, 196 | disabled=False, 197 | ), 198 | ) 199 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/entity.py: -------------------------------------------------------------------------------- 1 | """MQTT component mixins and helpers.""" 2 | from homeassistant import config_entries 3 | from homeassistant.helpers.entity import DeviceInfo, Entity 4 | from homeassistant.util import slugify 5 | 6 | from .const import ( 7 | CONF_SERIAL_NUMBER, 8 | CONF_TOPIC_PREFIX, 9 | DEVICE_INFO_MANUFACTURER, 10 | DEVICE_INFO_MODEL, 11 | DOMAIN, 12 | ) 13 | from .definitions import GoEChargerEntityDescription 14 | 15 | 16 | class GoEChargerEntity(Entity): 17 | """Common go-eCharger entity.""" 18 | 19 | def __init__( 20 | self, 21 | config_entry: config_entries.ConfigEntry, 22 | description: GoEChargerEntityDescription, 23 | ) -> None: 24 | """Initialize the sensor.""" 25 | topic_prefix = config_entry.data[CONF_TOPIC_PREFIX] 26 | serial_number = config_entry.data[CONF_SERIAL_NUMBER] 27 | 28 | self._topic = f"{topic_prefix}/{serial_number}/{description.key}" 29 | 30 | slug = slugify(self._topic.replace("/", "_")) 31 | self.entity_id = f"{description.domain}.{slug}" 32 | 33 | self._attr_unique_id = "-".join( 34 | [serial_number, description.domain, description.key, description.attribute] 35 | ) 36 | self._attr_device_info = DeviceInfo( 37 | identifiers={(DOMAIN, serial_number)}, 38 | name=config_entry.title, 39 | manufacturer=DEVICE_INFO_MANUFACTURER, 40 | model=DEVICE_INFO_MODEL, 41 | ) 42 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "goecharger_mqtt", 3 | "name": "go-eCharger (MQTT)", 4 | "codeowners": [ 5 | "@syssi" 6 | ], 7 | "config_flow": true, 8 | "dependencies": ["mqtt"], 9 | "documentation": "https://github.com/syssi/homeassistant-goecharger-mqtt", 10 | "homekit": {}, 11 | "iot_class": "local_push", 12 | "issue_tracker": "https://github.com/syssi/homeassistant-goecharger-mqtt/issues", 13 | "mqtt": [ 14 | "go-eCharger/+/var", 15 | "/go-eCharger/+/var" 16 | ], 17 | "requirements": [], 18 | "ssdp": [], 19 | "version": "0.26.0", 20 | "zeroconf": [] 21 | } 22 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/number.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) switch.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.number import NumberEntity 7 | from homeassistant.core import callback 8 | 9 | from .definitions.number import NUMBERS, GoEChargerNumberEntityDescription 10 | from .entity import GoEChargerEntity 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | async def async_setup_entry( 16 | hass: core.HomeAssistant, 17 | config_entry: config_entries.ConfigEntry, 18 | async_add_entities, 19 | ): 20 | """Config entry setup.""" 21 | async_add_entities( 22 | GoEChargerNumber(config_entry, description) 23 | for description in NUMBERS 24 | if not description.disabled 25 | ) 26 | 27 | 28 | class GoEChargerNumber(GoEChargerEntity, NumberEntity): 29 | """Representation of a go-eCharger switch that is updated via MQTT.""" 30 | 31 | entity_description: GoEChargerNumberEntityDescription 32 | 33 | def __init__( 34 | self, 35 | config_entry: config_entries.ConfigEntry, 36 | description: GoEChargerNumberEntityDescription, 37 | ) -> None: 38 | """Initialize the sensor.""" 39 | super().__init__(config_entry, description) 40 | 41 | self.entity_description = description 42 | self._attr_available = False 43 | 44 | async def async_set_native_value(self, value: float) -> None: 45 | """Update the current value.""" 46 | if value == 0 and self.entity_description.treat_zero_as_null: 47 | await mqtt.async_publish(self.hass, f"{self._topic}/set", "null") 48 | elif self.native_step == 1: 49 | await mqtt.async_publish(self.hass, f"{self._topic}/set", int(value)) 50 | else: 51 | await mqtt.async_publish(self.hass, f"{self._topic}/set", value) 52 | 53 | async def async_added_to_hass(self): 54 | """Subscribe to MQTT events.""" 55 | 56 | @callback 57 | def message_received(message): 58 | """Handle new MQTT messages.""" 59 | self._attr_available = True 60 | if self.entity_description.state is not None: 61 | self._attr_native_value = self.entity_description.state( 62 | message.payload, self.entity_description.attribute 63 | ) 64 | else: 65 | if message.payload == "null": 66 | self._attr_native_value = None 67 | else: 68 | self._attr_native_value = message.payload 69 | 70 | self.async_write_ha_state() 71 | 72 | await mqtt.async_subscribe(self.hass, self._topic, message_received, 1) 73 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/select.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) switch.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.select import SelectEntity 7 | from homeassistant.core import callback 8 | 9 | from .definitions.select import SELECTS, GoEChargerSelectEntityDescription 10 | from .entity import GoEChargerEntity 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | async def async_setup_entry( 16 | hass: core.HomeAssistant, 17 | config_entry: config_entries.ConfigEntry, 18 | async_add_entities, 19 | ): 20 | """Config entry setup.""" 21 | async_add_entities( 22 | GoEChargerSelect(config_entry, description) 23 | for description in SELECTS 24 | if not description.disabled 25 | ) 26 | 27 | 28 | class GoEChargerSelect(GoEChargerEntity, SelectEntity): 29 | """Representation of a go-eCharger switch that is updated via MQTT.""" 30 | 31 | entity_description: GoEChargerSelectEntityDescription 32 | 33 | def __init__( 34 | self, 35 | config_entry: config_entries.ConfigEntry, 36 | description: GoEChargerSelectEntityDescription, 37 | ) -> None: 38 | """Initialize the sensor.""" 39 | super().__init__(config_entry, description) 40 | 41 | self.entity_description = description 42 | self._attr_options = list(description.legacy_options.values()) 43 | self._attr_current_option = None 44 | 45 | @property 46 | def available(self): 47 | """Return True if entity is available.""" 48 | return self._attr_current_option is not None 49 | 50 | def key_from_option(self, option: str): 51 | """Return the option a given payload is assigned to.""" 52 | try: 53 | return next( 54 | key 55 | for key, value in self.entity_description.legacy_options.items() 56 | if value == option 57 | ) 58 | except StopIteration: 59 | return None 60 | 61 | async def async_select_option(self, option: str) -> None: 62 | """Update the current value.""" 63 | await mqtt.async_publish( 64 | self.hass, f"{self._topic}/set", self.key_from_option(option) 65 | ) 66 | 67 | async def async_added_to_hass(self): 68 | """Subscribe to MQTT events.""" 69 | 70 | @callback 71 | def message_received(message): 72 | """Handle new MQTT messages.""" 73 | if self.entity_description.state is not None: 74 | self._attr_current_option = self.entity_description.state( 75 | message.payload, self.entity_description.attribute 76 | ) 77 | else: 78 | payload = message.payload 79 | # if payload is None or payload in ["null", "none"]: 80 | # return 81 | 82 | if payload not in self.entity_description.legacy_options.keys(): 83 | _LOGGER.error( 84 | "Invalid option for %s: '%s' (valid options: %s)", 85 | self.entity_id, 86 | payload, 87 | self.options, 88 | ) 89 | return 90 | 91 | self._attr_current_option = self.entity_description.legacy_options[ 92 | payload 93 | ] 94 | 95 | self.async_write_ha_state() 96 | 97 | await mqtt.async_subscribe(self.hass, self._topic, message_received, 1) 98 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/sensor.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) sensor.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.sensor import SensorEntity 7 | from homeassistant.core import callback 8 | 9 | from .definitions.sensor import SENSORS, GoEChargerSensorEntityDescription 10 | from .entity import GoEChargerEntity 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | async def async_setup_entry( 16 | hass: core.HomeAssistant, 17 | config_entry: config_entries.ConfigEntry, 18 | async_add_entities, 19 | ): 20 | """Config entry setup.""" 21 | 22 | # _LOGGER.debug( 23 | # "| Key | Friendly name | Category | Unit | Enabled per default | Supported | Unsupported reason |" 24 | # ) 25 | # _LOGGER.debug( 26 | # "| --- | ------------- | -------- | ---- | ------------------- | --------- | ------------------ |" 27 | # ) 28 | # for description in SENSORS: 29 | # entity_registry_enabled = ( 30 | # ":heavy_check_mark:" 31 | # if description.entity_registry_enabled_default 32 | # else ":white_large_square:" 33 | # ) 34 | # supported = ":heavy_check_mark:" if not description.disabled else ":x:" 35 | # reason = ( 36 | # "[^1]" 37 | # if description.disabled_reason == "Not exposed via MQTT in firmware 053.1" 38 | # else description.disabled_reason 39 | # ) 40 | # native_unit_of_measurement = ( 41 | # "" 42 | # if description.native_unit_of_measurement is None 43 | # else description.native_unit_of_measurement 44 | # ) 45 | # entity_category = ( 46 | # "" 47 | # if description.entity_category is None 48 | # else f"`{description.entity_category}`" 49 | # ) 50 | # _LOGGER.debug( 51 | # f"| `{description.key}` | {description.name} | {entity_category} | {native_unit_of_measurement} | {entity_registry_enabled} | {supported} | {reason} |" 52 | # ) 53 | 54 | async_add_entities( 55 | GoEChargerSensor(config_entry, description) 56 | for description in SENSORS 57 | if not description.disabled 58 | ) 59 | 60 | 61 | class GoEChargerSensor(GoEChargerEntity, SensorEntity): 62 | """Representation of a go-eCharger sensor that is updated via MQTT.""" 63 | 64 | entity_description: GoEChargerSensorEntityDescription 65 | 66 | def __init__( 67 | self, 68 | config_entry: config_entries.ConfigEntry, 69 | description: GoEChargerSensorEntityDescription, 70 | ) -> None: 71 | """Initialize the sensor.""" 72 | super().__init__(config_entry, description) 73 | 74 | self.entity_description = description 75 | 76 | @property 77 | def available(self): 78 | """Return True if entity is available.""" 79 | return self._attr_native_value is not None 80 | 81 | async def async_added_to_hass(self): 82 | """Subscribe to MQTT events.""" 83 | 84 | @callback 85 | def message_received(message): 86 | """Handle new MQTT messages.""" 87 | if self.entity_description.state is not None: 88 | self._attr_native_value = self.entity_description.state( 89 | message.payload, self.entity_description.attribute 90 | ) 91 | else: 92 | if message.payload == "null": 93 | self._attr_native_value = None 94 | else: 95 | self._attr_native_value = message.payload 96 | 97 | self.async_write_ha_state() 98 | 99 | await mqtt.async_subscribe(self.hass, self._topic, message_received, 1) 100 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/services.yaml: -------------------------------------------------------------------------------- 1 | set_config_key: 2 | name: Set config key 3 | description: Sets a config key to a provided value. 4 | fields: 5 | serial_number: 6 | name: Serial number 7 | description: The serial number of the go-e device. 8 | example: 012345 9 | required: true 10 | selector: 11 | text: 12 | key: 13 | name: Config key 14 | description: The key of the config parameter you want to change. 15 | example: fna 16 | required: true 17 | selector: 18 | select: 19 | options: 20 | - acp 21 | - acs 22 | - ama 23 | - amp 24 | - ara 25 | - ate 26 | - att 27 | - awc 28 | - awe 29 | - awp 30 | - awpl 31 | - bac 32 | - cch 33 | - cco 34 | - cfi 35 | - cid 36 | - clp 37 | - ct 38 | - cwc 39 | - cwe 40 | - dwo 41 | - esk 42 | - fna 43 | - frc 44 | - fup 45 | - hsa 46 | - hws 47 | - ids 48 | - Key 49 | - lmo 50 | - loe 51 | - lof 52 | - log 53 | - lop 54 | - lot 55 | - loty 56 | - lse 57 | - map 58 | - mca 59 | - mci 60 | - mcpd 61 | - mcpea 62 | - mptwt 63 | - mpwst 64 | - nmo 65 | - pgt 66 | - psmd 67 | - sch_satur 68 | - sch_sund 69 | - sch_week 70 | - sdp 71 | - spl3 72 | - su 73 | - sua 74 | - sumd 75 | - tds 76 | - tof 77 | - tse 78 | - trx 79 | - upo 80 | - ust 81 | - utc 82 | - wak 83 | - wan 84 | - wen 85 | - wifis 86 | value: 87 | name: Value 88 | description: The new value to set for this config parameter. 89 | example: "go-e" 90 | required: true 91 | selector: 92 | text: 93 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "flow_title": "{name}", 4 | "step": { 5 | "discovery_confirm": { 6 | "description": "[%key:common::config_flow::description%]" 7 | }, 8 | "user": { 9 | "description": "[%key:common::config_flow::description%]", 10 | "data": { 11 | "serial_number": "[%key:common::config_flow::data::serial_number%]", 12 | "topic_prefix": "[%key:common::config_flow::data::topic_prefix%]" 13 | } 14 | } 15 | }, 16 | "error": { 17 | "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", 18 | "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", 19 | "unknown": "[%key:common::config_flow::error::unknown%]" 20 | }, 21 | "abort": { 22 | "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/switch.py: -------------------------------------------------------------------------------- 1 | """The go-eCharger (MQTT) switch.""" 2 | import logging 3 | 4 | from homeassistant import config_entries, core 5 | from homeassistant.components import mqtt 6 | from homeassistant.components.switch import SwitchEntity 7 | from homeassistant.core import callback 8 | 9 | from .definitions.switch import SWITCHES, GoEChargerSwitchEntityDescription 10 | from .entity import GoEChargerEntity 11 | 12 | _LOGGER = logging.getLogger(__name__) 13 | 14 | 15 | async def async_setup_entry( 16 | hass: core.HomeAssistant, 17 | config_entry: config_entries.ConfigEntry, 18 | async_add_entities, 19 | ): 20 | """Config entry setup.""" 21 | async_add_entities( 22 | GoEChargerSwitch(config_entry, description) 23 | for description in SWITCHES 24 | if not description.disabled 25 | ) 26 | 27 | 28 | class GoEChargerSwitch(GoEChargerEntity, SwitchEntity): 29 | """Representation of a go-eCharger switch that is updated via MQTT.""" 30 | 31 | entity_description: GoEChargerSwitchEntityDescription 32 | 33 | def __init__( 34 | self, 35 | config_entry: config_entries.ConfigEntry, 36 | description: GoEChargerSwitchEntityDescription, 37 | ) -> None: 38 | """Initialize the sensor.""" 39 | super().__init__(config_entry, description) 40 | 41 | self.entity_description = description 42 | self._optimistic = self.entity_description.optimistic 43 | 44 | @property 45 | def available(self): 46 | """Return True if entity is available.""" 47 | if self._optimistic: 48 | return self._topic is not None 49 | 50 | return self._topic is not None 51 | 52 | @property 53 | def assumed_state(self): 54 | """Return true if we do optimistic updates.""" 55 | return self._optimistic 56 | 57 | async def async_turn_on(self, **kwargs): 58 | """Turn the switch on.""" 59 | await mqtt.async_publish( 60 | self.hass, f"{self._topic}/set", self.entity_description.payload_on 61 | ) 62 | if self._optimistic: 63 | # Optimistically assume that switch has changed state. 64 | self._attr_is_on = True 65 | self.async_write_ha_state() 66 | 67 | async def async_turn_off(self, **kwargs): 68 | """Turn the switch off.""" 69 | await mqtt.async_publish( 70 | self.hass, f"{self._topic}/set", self.entity_description.payload_off 71 | ) 72 | if self._optimistic: 73 | # Optimistically assume that switch has changed state. 74 | self._attr_is_on = False 75 | self.async_write_ha_state() 76 | 77 | async def async_added_to_hass(self): 78 | """Subscribe to MQTT events.""" 79 | 80 | @callback 81 | def message_received(message): 82 | """Handle new MQTT messages.""" 83 | if self.entity_description.state is not None: 84 | self._attr_is_on = self.entity_description.state( 85 | message.payload, self.entity_description.attribute 86 | ) 87 | else: 88 | if message.payload == self.entity_description.payload_on: 89 | self._attr_is_on = True 90 | elif message.payload == self.entity_description.payload_off: 91 | self._attr_is_on = False 92 | else: 93 | self._attr_is_on = None 94 | 95 | self.async_write_ha_state() 96 | 97 | await mqtt.async_subscribe(self.hass, self._topic, message_received, 1) 98 | -------------------------------------------------------------------------------- /custom_components/goecharger_mqtt/translations/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "abort": { 4 | "already_configured": "Device is already configured" 5 | }, 6 | "flow_title": "{name}", 7 | "error": { 8 | "cannot_connect": "Failed to connect", 9 | "invalid_auth": "Invalid authentication", 10 | "unknown": "Unexpected error" 11 | }, 12 | "step": { 13 | "discovery_confirm": { 14 | "description": "Do you want to setup {name}?" 15 | }, 16 | "user": { 17 | "description": "Please provide the serial number of your device", 18 | "data": { 19 | "serial_number": "Serial number", 20 | "topic_prefix": "Base topic" 21 | } 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /hacs.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "go-eCharger integration for Home Assistant using the MQTT API", 3 | "content_in_root": false, 4 | "render_readme": true, 5 | "homeassistant": "2022.12.0" 6 | } 7 | -------------------------------------------------------------------------------- /lovelace-entities-card-config.yaml: -------------------------------------------------------------------------------- 1 | type: entities 2 | entities: 3 | - switch.go_echarger_072246_bac 4 | - switch.go_echarger_072246_ara 5 | - number.go_echarger_072246_amp 6 | - sensor.go_echarger_072246_ama 7 | - sensor.go_echarger_072246_mca 8 | - sensor.go_echarger_072246_psm 9 | - sensor.go_echarger_072246_spl3 10 | - sensor.go_echarger_072246_ate 11 | - sensor.go_echarger_072246_att 12 | - sensor.go_echarger_072246_dwo 13 | - sensor.go_echarger_072246_awp 14 | - sensor.go_echarger_072246_ust 15 | - select.go_echarger_072246_ust 16 | - sensor.go_echarger_072246_frc 17 | - select.go_echarger_072246_frc 18 | - sensor.go_echarger_072246_lmo 19 | - select.go_echarger_072246_lmo 20 | - sensor.go_echarger_072246_lbr 21 | - sensor.go_echarger_072246_cch 22 | - sensor.go_echarger_072246_cfi 23 | - sensor.go_echarger_072246_cid 24 | - sensor.go_echarger_072246_cwc 25 | - sensor.go_echarger_072246_result 26 | title: Configuration 27 | show_header_toggle: false 28 | state_color: false 29 | -------------------------------------------------------------------------------- /lovelace-entities-card-device.yaml: -------------------------------------------------------------------------------- 1 | type: entities 2 | entities: 3 | - sensor.go_echarger_072246_var 4 | - sensor.go_echarger_072246_fwv 5 | title: Device 6 | -------------------------------------------------------------------------------- /lovelace-entities-card-diagnostics.yaml: -------------------------------------------------------------------------------- 1 | type: entities 2 | entities: 3 | - entity: switch.go_echarger_072246_psm 4 | - entity: sensor.go_echarger_072246_car 5 | - entity: sensor.go_echarger_072246_modelstatus 6 | - entity: sensor.go_echarger_072246_err 7 | - entity: sensor.go_echarger_072246_cdi_2 8 | - entity: sensor.go_echarger_072246_cbl 9 | - entity: sensor.go_echarger_072246_tpa 10 | - entity: sensor.go_echarger_072246_eto 11 | - entity: sensor.go_echarger_072246_wh 12 | - entity: sensor.go_echarger_072246_cards 13 | - entity: sensor.go_echarger_072246_cards_2 14 | - entity: sensor.go_echarger_072246_cards_3 15 | - entity: sensor.go_echarger_072246_cards_4 16 | - entity: sensor.go_echarger_072246_trx 17 | - entity: sensor.go_echarger_072246_acu 18 | - entity: binary_sensor.go_echarger_072246_adi 19 | - entity: sensor.go_echarger_072246_tma_3 20 | - entity: sensor.go_echarger_072246_tma_4 21 | - entity: sensor.go_echarger_072246_amt 22 | - entity: sensor.go_echarger_072246_rbc 23 | - entity: sensor.go_echarger_072246_rssi 24 | title: Diagnostics 25 | -------------------------------------------------------------------------------- /mqtt-capture.log: -------------------------------------------------------------------------------- 1 | /go-eCharger/000001/acs 0 2 | /go-eCharger/000001/acu 10 3 | /go-eCharger/000001/adi true 4 | /go-eCharger/000001/alw true 5 | /go-eCharger/000001/ama 16 6 | /go-eCharger/000001/amp 10 7 | /go-eCharger/000001/amt 32 8 | /go-eCharger/000001/ara true 9 | /go-eCharger/000001/ate 18000 10 | /go-eCharger/000001/att 21600 11 | /go-eCharger/000001/awcp {"start":1645038000,"end":1645041600,"marketprice":19.395} 12 | /go-eCharger/000001/awp 3 13 | /go-eCharger/000001/bac true 14 | /go-eCharger/000001/car 1 15 | /go-eCharger/000001/cards [{"name":"User 1","energy":0,"cardId":true},{"name":"User 2","energy":0,"cardId":false},{"name":"User 3","energy":0,"cardId":false},{"name":"User 4","energy":0,"cardId":false},{"name":"User 5","energy":0,"cardId":false},{"name":"User 6","energy":0,"cardId":false},{"name":"User 7","energy":0,"cardId":false},{"name":"User 8","energy":0,"cardId":false},{"name":"User 9","energy":0,"cardId":false},{"name":"User 10","energy":0,"cardId":false}] 16 | /go-eCharger/000001/cbl null 17 | /go-eCharger/000001/cch "#00FFFF" 18 | /go-eCharger/000001/ccw {"ssid":"redacted", "redacted": "redacted"} 19 | /go-eCharger/000001/cdi {"type":1,"value":0} 20 | /go-eCharger/000001/cfi "#00FF00" 21 | /go-eCharger/000001/cid "#0000FF" 22 | /go-eCharger/000001/clp [6,10,12,14,16] 23 | /go-eCharger/000001/cwc "#FFFF00" 24 | /go-eCharger/000001/deltap 0 25 | /go-eCharger/000001/dll "https://data.v3.go-e.io/export?e=redacted" 26 | /go-eCharger/000001/dns {"dns":"0.0.0.0"} 27 | /go-eCharger/000001/dwo null 28 | /go-eCharger/000001/err 0 29 | /go-eCharger/000001/eto 0 30 | /go-eCharger/000001/fhz 49.774 31 | /go-eCharger/000001/fhz 49.83 32 | /go-eCharger/000001/fhz 49.88 33 | /go-eCharger/000001/fhz 49.884 34 | /go-eCharger/000001/fhz 49.897 35 | /go-eCharger/000001/fhz 49.898 36 | /go-eCharger/000001/fhz 49.909 37 | /go-eCharger/000001/fhz 49.915 38 | /go-eCharger/000001/fhz 49.919 39 | /go-eCharger/000001/fhz 49.921 40 | /go-eCharger/000001/fhz 49.926 41 | /go-eCharger/000001/fhz 49.933 42 | /go-eCharger/000001/fhz 49.939 43 | /go-eCharger/000001/fhz 50.023 44 | /go-eCharger/000001/fhz 50.043 45 | /go-eCharger/000001/fhz 50.111 46 | /go-eCharger/000001/frc 0 47 | /go-eCharger/000001/fsp false 48 | /go-eCharger/000001/fwv "053.1" 49 | /go-eCharger/000001/hla false 50 | /go-eCharger/000001/lbp null 51 | /go-eCharger/000001/lbr 255 52 | /go-eCharger/000001/lccfc null 53 | /go-eCharger/000001/lccfi null 54 | /go-eCharger/000001/lcctc null 55 | /go-eCharger/000001/lmo 3 56 | /go-eCharger/000001/lmsc 1608 57 | /go-eCharger/000001/loa null 58 | /go-eCharger/000001/loc "2022-02-16T20:27:34.043.167 +01:00" 59 | /go-eCharger/000001/loc "2022-02-16T20:27:35.108.686 +01:00" 60 | /go-eCharger/000001/loc "2022-02-16T20:27:36.039.346 +01:00" 61 | /go-eCharger/000001/loc "2022-02-16T20:27:37.037.827 +01:00" 62 | /go-eCharger/000001/loc "2022-02-16T20:27:38.039.326 +01:00" 63 | /go-eCharger/000001/loc "2022-02-16T20:27:39.041.830 +01:00" 64 | /go-eCharger/000001/loc "2022-02-16T20:27:40.361.504 +01:00" 65 | /go-eCharger/000001/loc "2022-02-16T20:27:41.362.271 +01:00" 66 | /go-eCharger/000001/loc "2022-02-16T20:27:42.039.266 +01:00" 67 | /go-eCharger/000001/loc "2022-02-16T20:27:43.038.220 +01:00" 68 | /go-eCharger/000001/loc "2022-02-16T20:27:44.038.835 +01:00" 69 | /go-eCharger/000001/loc "2022-02-16T20:27:45.039.331 +01:00" 70 | /go-eCharger/000001/loc "2022-02-16T20:27:46.037.905 +01:00" 71 | /go-eCharger/000001/loc "2022-02-16T20:27:47.037.725 +01:00" 72 | /go-eCharger/000001/loc "2022-02-16T20:27:48.038.986 +01:00" 73 | /go-eCharger/000001/loc "2022-02-16T20:27:49.040.081 +01:00" 74 | /go-eCharger/000001/lrc null 75 | /go-eCharger/000001/lri null 76 | /go-eCharger/000001/lrr null 77 | /go-eCharger/000001/mca 6 78 | /go-eCharger/000001/men false 79 | /go-eCharger/000001/modelStatus 15 80 | /go-eCharger/000001/nrg [15,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0] 81 | /go-eCharger/000001/nrg [15,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0] 82 | /go-eCharger/000001/nrg [15,0,0,222,0,0,0,0,0,0,0,0,0,0,0,0] 83 | /go-eCharger/000001/nrg [15,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0] 84 | /go-eCharger/000001/ocu ["052.2","V 051.9 OUTDATED","V 052.0 OUTDATED","V 052.1 OUTDATED","V 053.0 BETA","V 053.1 BETA"] 85 | /go-eCharger/000001/pakku null 86 | /go-eCharger/000001/pgrid null 87 | /go-eCharger/000001/pha [false,false,false,true,false,false] 88 | /go-eCharger/000001/ppv null 89 | /go-eCharger/000001/psm 2 90 | /go-eCharger/000001/rbc 7 91 | /go-eCharger/000001/rbt 9563735 92 | /go-eCharger/000001/rbt 9564801 93 | /go-eCharger/000001/rbt 9565732 94 | /go-eCharger/000001/rbt 9566730 95 | /go-eCharger/000001/rbt 9567732 96 | /go-eCharger/000001/rbt 9568734 97 | /go-eCharger/000001/rbt 9570054 98 | /go-eCharger/000001/rbt 9571055 99 | /go-eCharger/000001/rbt 9571731 100 | /go-eCharger/000001/rbt 9572730 101 | /go-eCharger/000001/rbt 9573731 102 | /go-eCharger/000001/rbt 9574732 103 | /go-eCharger/000001/rbt 9575730 104 | /go-eCharger/000001/rbt 9576730 105 | /go-eCharger/000001/rbt 9577731 106 | /go-eCharger/000001/rbt 9578733 107 | /go-eCharger/000001/rssi -42 108 | /go-eCharger/000001/rssi -44 109 | /go-eCharger/000001/rssi -45 110 | /go-eCharger/000001/rssi -46 111 | /go-eCharger/000001/spl3 4200 112 | /go-eCharger/000001/tma [24.125,28.125] 113 | /go-eCharger/000001/tma [24.125,28.25] 114 | /go-eCharger/000001/tma [24.25,28.25] 115 | /go-eCharger/000001/tpa 0 116 | /go-eCharger/000001/trx null 117 | /go-eCharger/000001/ust 0 118 | /go-eCharger/000001/utc "2022-02-16T19:27:34.042.171" 119 | /go-eCharger/000001/utc "2022-02-16T19:27:35.107.704" 120 | /go-eCharger/000001/utc "2022-02-16T19:27:36.038.333" 121 | /go-eCharger/000001/utc "2022-02-16T19:27:37.036.836" 122 | /go-eCharger/000001/utc "2022-02-16T19:27:38.038.339" 123 | /go-eCharger/000001/utc "2022-02-16T19:27:39.040.895" 124 | /go-eCharger/000001/utc "2022-02-16T19:27:40.360.553" 125 | /go-eCharger/000001/utc "2022-02-16T19:27:41.361.176" 126 | /go-eCharger/000001/utc "2022-02-16T19:27:42.038.297" 127 | /go-eCharger/000001/utc "2022-02-16T19:27:43.037.229" 128 | /go-eCharger/000001/utc "2022-02-16T19:27:44.037.704" 129 | /go-eCharger/000001/utc "2022-02-16T19:27:45.038.170" 130 | /go-eCharger/000001/utc "2022-02-16T19:27:46.036.941" 131 | /go-eCharger/000001/utc "2022-02-16T19:27:47.036.587" 132 | /go-eCharger/000001/utc "2022-02-16T19:27:48.037.860" 133 | /go-eCharger/000001/utc "2022-02-16T19:27:49.039.121" 134 | /go-eCharger/000001/var 11 135 | /go-eCharger/000001/wh 0 136 | -------------------------------------------------------------------------------- /requirements.test.txt: -------------------------------------------------------------------------------- 1 | # Strictly for tests 2 | pytest 3 | pytest-cov<3.0.0 4 | pytest-homeassistant-custom-component>=0.4.8 5 | aiohttp_cors 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [coverage:run] 2 | source = 3 | custom_components 4 | 5 | [coverage:report] 6 | exclude_lines = 7 | pragma: no cover 8 | raise NotImplemented() 9 | if __name__ == '__main__': 10 | main() 11 | #fail_under = 93 12 | fail_under = 10 13 | show_missing = true 14 | 15 | [tool:pytest] 16 | testpaths = tests 17 | norecursedirs = .git 18 | addopts = 19 | --strict 20 | --cov=custom_components 21 | 22 | [flake8] 23 | # https://github.com/ambv/black#line-length 24 | max-line-length = 88 25 | # E501: line too long 26 | # W503: Line break occurred before a binary operator 27 | # E203: Whitespace before ':' 28 | # D202 No blank lines allowed after function docstring 29 | # W504 line break after binary operator 30 | ignore = 31 | E501, 32 | W503, 33 | E203, 34 | D202, 35 | W504 36 | 37 | [isort] 38 | # https://github.com/timothycrosley/isort 39 | # https://github.com/timothycrosley/isort/wiki/isort-Settings 40 | # splits long import on multiple lines indented by 4 spaces 41 | multi_line_output = 3 42 | include_trailing_comma=True 43 | force_grid_wrap=0 44 | use_parentheses=True 45 | line_length=88 46 | indent = " " 47 | # will group `import x` and `from x import` of the same module. 48 | force_sort_within_sections = true 49 | sections = FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER 50 | default_section = THIRDPARTY 51 | known_first_party = custom_components,tests 52 | forced_separate = tests 53 | combine_as_imports = true 54 | 55 | [mypy] 56 | python_version = 3.7 57 | ignore_errors = true 58 | follow_imports = silent 59 | ignore_missing_imports = true 60 | warn_incomplete_stub = true 61 | warn_redundant_casts = true 62 | warn_unused_configs = true 63 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Tests for the go-eCharger (MQTT) integration.""" 2 | -------------------------------------------------------------------------------- /tests/bandit.yaml: -------------------------------------------------------------------------------- 1 | # https://bandit.readthedocs.io/en/latest/config.html 2 | 3 | tests: 4 | - B108 5 | - B306 6 | - B307 7 | - B313 8 | - B314 9 | - B315 10 | - B316 11 | - B317 12 | - B318 13 | - B319 14 | - B320 15 | - B325 16 | - B602 17 | - B604 18 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | """pytest fixtures.""" 2 | from unittest.mock import MagicMock 3 | 4 | from homeassistant import core as ha 5 | from homeassistant.components import mqtt 6 | from homeassistant.setup import async_setup_component 7 | import pytest 8 | 9 | 10 | @ha.callback 11 | def mock_component(hass, component): 12 | """Mock a component is setup.""" 13 | if component in hass.config.components: 14 | AssertionError(f"Integration {component} is already setup") 15 | 16 | hass.config.components.add(component) 17 | 18 | 19 | @pytest.fixture(autouse=True) 20 | def auto_enable_custom_integrations(enable_custom_integrations): 21 | """Enable custom integrations defined in the test dir.""" 22 | yield 23 | 24 | 25 | @pytest.fixture(autouse=True) 26 | def mock_dependencies(hass): 27 | """Mock dependencies loaded.""" 28 | mock_component(hass, "mqtt") 29 | 30 | 31 | @pytest.fixture 32 | async def mqtt_mock(hass, mqtt_client_mock, mqtt_config): 33 | """Fixture to mock MQTT component.""" 34 | if mqtt_config is None: 35 | mqtt_config = {mqtt.CONF_BROKER: "mock-broker", mqtt.CONF_BIRTH_MESSAGE: {}} 36 | 37 | result = await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: mqtt_config}) 38 | assert result 39 | await hass.async_block_till_done() 40 | 41 | # Workaround: asynctest==0.13 fails on @functools.lru_cache 42 | spec = dir(hass.data["mqtt"]) 43 | spec.remove("_matching_subscriptions") 44 | 45 | mqtt_component_mock = MagicMock( 46 | return_value=hass.data["mqtt"], 47 | spec_set=spec, 48 | wraps=hass.data["mqtt"], 49 | ) 50 | mqtt_component_mock._mqttc = mqtt_client_mock 51 | 52 | hass.data["mqtt"] = mqtt_component_mock 53 | component = hass.data["mqtt"] 54 | component.reset_mock() 55 | return component 56 | -------------------------------------------------------------------------------- /tests/test_config_flow.py: -------------------------------------------------------------------------------- 1 | """Test the go-eCharger (MQTT) config flow.""" 2 | from unittest.mock import patch 3 | 4 | from homeassistant import config_entries 5 | from homeassistant.core import HomeAssistant 6 | from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM 7 | 8 | from custom_components.goecharger_mqtt.config_flow import CannotConnect 9 | from custom_components.goecharger_mqtt.const import DOMAIN 10 | 11 | 12 | async def test_form(hass: HomeAssistant) -> None: 13 | """Test we get the form.""" 14 | result = await hass.config_entries.flow.async_init( 15 | DOMAIN, context={"source": config_entries.SOURCE_USER} 16 | ) 17 | assert result["type"] == RESULT_TYPE_FORM 18 | assert result["errors"] is None 19 | 20 | with patch( 21 | "custom_components.goecharger_mqtt.config_flow.PlaceholderHub.validate_device_topic", 22 | return_value=True, 23 | ), patch( 24 | "custom_components.goecharger_mqtt.async_setup_entry", return_value=True 25 | ) as mock_setup_entry: 26 | result2 = await hass.config_entries.flow.async_configure( 27 | result["flow_id"], 28 | {"serial_number": "012345", "topic_prefix": "/go-eCharger"}, 29 | ) 30 | await hass.async_block_till_done() 31 | 32 | assert result2["type"] == RESULT_TYPE_CREATE_ENTRY 33 | assert result2["title"] == "go-eCharger 012345" 34 | assert result2["data"] == { 35 | "serial_number": "012345", 36 | "topic_prefix": "/go-eCharger", 37 | } 38 | assert len(mock_setup_entry.mock_calls) == 1 39 | 40 | 41 | async def test_form_cannot_connect(hass: HomeAssistant) -> None: 42 | """Test we handle cannot connect error.""" 43 | result = await hass.config_entries.flow.async_init( 44 | DOMAIN, context={"source": config_entries.SOURCE_USER} 45 | ) 46 | 47 | with patch( 48 | "custom_components.goecharger_mqtt.config_flow.PlaceholderHub.validate_device_topic", 49 | side_effect=CannotConnect, 50 | ): 51 | result2 = await hass.config_entries.flow.async_configure( 52 | result["flow_id"], 53 | {"serial_number": "012345", "topic_prefix": "/go-eCharger"}, 54 | ) 55 | 56 | assert result2["type"] == RESULT_TYPE_FORM 57 | assert result2["errors"] == {"base": "cannot_connect"} 58 | --------------------------------------------------------------------------------