Skip to content

Comments

[mideaac] Initial contribution#17749

Merged
lsiepel merged 44 commits intoopenhab:mainfrom
apella12:separate-connection-manager
Nov 6, 2025
Merged

[mideaac] Initial contribution#17749
lsiepel merged 44 commits intoopenhab:mainfrom
apella12:separate-connection-manager

Conversation

@apella12
Copy link
Contributor

This is a second attempt. The first attempt is closed #17395. Essentially all of the previous comments have been addressed. The main new change is the separation of the connection manager and the MideaACHandler, (largely rewritten by @lsiepel) these two files are basically new. I have worked and tested with this version (made some modifications) for several weeks and it seems to work as well as the first attempt now. Also there were a number of new supporting files added by @lsiepel.

For reference the previous intro is here.
I’d like to put this out for new binding review.
This binding was started by the original author as a forum topic but has since had other contributors. I picked it up when I installed a mini-split AC that used the Midea protocol earlier this year, originally to allow for longer polling frequencies. Then as a retirement challenge (no formal java training), decided to attempt to clean it up for official status. I cleaned up the summary report from over 150 items and believe I conformed to current developer guidelines (Java docs, naming, tests, etc.). Along the way added some additional functionality and corrected some code issues.
The discovery and security classes remain largely unchanged from the original author (who I haven’t been able to contact), and work well. The other classes I understand pretty well at this point and hopefully can address any concerns.
As a note, to conform to the guidelines there are breaking changes in naming from the version I published on the forum thread.

@apella12 apella12 requested a review from a team as a code owner November 15, 2024 15:08
@apella12 apella12 changed the title [Mideaac] Initial contribution- second try [mideaac] Initial contribution- second try Nov 15, 2024
@jlaur jlaur added the new binding If someone has started to work on a binding. For a new binding PR. label Nov 15, 2024
@apella12 apella12 force-pushed the separate-connection-manager branch 2 times, most recently from 8fae5fa to 44bb90f Compare December 17, 2024 21:34
@apella12 apella12 force-pushed the separate-connection-manager branch from 4ef6b08 to 071c1e7 Compare January 3, 2025 15:29
@lsiepel
Copy link
Contributor

lsiepel commented Jan 3, 2025

This is not forgotten, the time I have to spare is consumed by the ZUI binding at the moment. So don’t wait for me.

@apella12
Copy link
Contributor Author

apella12 commented Jan 3, 2025

@lsiepel Well I'm not really waiting. I'm working on other things too. There shouldn't be much to review after you rewrote the connection manager. I did a few things to make it more robust to run without the A/C connected to the cloud and fixed some things that you left hanging. I have had it polling for months without issues. It is not exactly A/C season, so no one is exactly clamoring for an update. Hopefully you or someone else can have a look in a couple of months as we get towards spring. EDIT: I did update the version to OH5 and change the date to 2025 in the headers

@apella12 apella12 force-pushed the separate-connection-manager branch from 7350e50 to 02ae747 Compare February 19, 2025 14:56
@lsiepel
Copy link
Contributor

lsiepel commented Feb 19, 2025

Forgot about this one, sorry. I might have some time to review in the next days.
It was tested and all works as expected?

@lsiepel lsiepel self-requested a review February 19, 2025 15:29
@apella12
Copy link
Contributor Author

Yes, it is working fine. I have been using it since the last commit. Decided to rebase today in case something in the OH5.0 causes a problem, but it passed checks

Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for not leaving this PR/binding. It has improved, i also see more room for improvement. Besides some new minor issues that i probably missed before, i think the DTO and connection structure can benefit from some more work and thinking.

Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marked some previous comments as resolved. Found some new ones, but nothing big. Let's slowly continue and narrow the remaining issues down and fix them together.

@apella12
Copy link
Contributor Author

apella12 commented Feb 20, 2025

In no particular order, 1) I'm not sure how to use the OH standard conversions and where to put the .toLowerCase since I do not see that in the documentation. 2) The exception in the retry I'm trying to address is simply a timeout. 3) Elsewhere, I was trying to avoid breaking something that I fixed earlier would cause me to go back and fix again. It has been months and I'm not recalling all the issues I had getting to the fix. 4) I also attached a log of the DTO actions, it appears to me everything is needed. The only logic is to pull from the cloud responses to compose the next message.

EDIT: Regaring other comments;
First about the blocking method in the initialize(). The issue is that V.3 discovery is two steps. First step is to get the IP, port, deviceId and set the defaults. The V.3 initialization starts but hits a wall until the cloud provider, email and password are entered on the UI page (V.2 OK). That springs the method to get the token and key. We could force textual configuration and the use of a third party platform to obtain the token and key, but that doesn’t seem to fit the OH model.

Second I retested a change to remind myself of the problem. I dropped the return after getTokenKeyCloud(cloudProvider); (line 218) and the initialize() after logger.debug("Token and Key obtained from cloud, saving, back to initialize"); (line 372). The token and key are filled in on the UI, the connection manager is started, but chokes on the authorization. Resaving the thing with a change corrects the problem (I just added a location), but that is messy. With the current code everything works seamlessly when deleting the token and key when the cloud provider, password and email are in place.

@apella12
Copy link
Contributor Author

Figured out how to leverage the OH core util hex/byte and separated the socket timeout exception from anything else. Seems to still work, but with the magnitude of changes am testing overnight. Have tested scan, retrieve key/token, normal polling and temperature changes. Had one timeout exception that worked as expected. 9 seconds = 4 for timeout and 5 delay for next try.

2025-02-21 17:19:56.320 [DEBUG] [nternal.connection.ConnectionManager] - Disconnecting from device at 192.168.0.246
2025-02-21 17:20:05.326 [DEBUG] [nternal.connection.ConnectionManager] - Socket retry count 1, Socket timeout connecting to 192.168.0.246: Connect timed out
2025-02-21 17:20:05.329 [DEBUG] [nternal.connection.ConnectionManager] - Device at IP: 192.168.0.246 requires authentication, going to authenticate

Normal connection is less that 10ms.

2025-02-21 17:09:53.751 [DEBUG] [nternal.connection.ConnectionManager] - Disconnecting from device at 192.168.0.246
2025-02-21 17:09:53.757 [DEBUG] [nternal.connection.ConnectionManager] - Device at IP: 192.168.0.246 requires authentication, going to authenticate

@apella12 apella12 force-pushed the separate-connection-manager branch 3 times, most recently from 2bb3b9c to 1a97cd8 Compare February 27, 2025 15:54
@apella12 apella12 force-pushed the separate-connection-manager branch from ab0cad5 to 6486564 Compare April 9, 2025 20:11
@apella12 apella12 force-pushed the separate-connection-manager branch from 03e5fbc to 00ea689 Compare May 9, 2025 23:19
@apella12 apella12 requested a review from lsiepel May 10, 2025 01:52
@lsiepel
Copy link
Contributor

lsiepel commented Jul 6, 2025

Ok, so i'll try to reboot this review proces, where are we with this PR? Previously we tried to seperate the handler and the connection manager, how did that work out?

@lsiepel lsiepel requested a review from Copilot July 6, 2025 11:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Initial contribution of the MideaAC binding, introducing the core implementation, tests, and OpenHAB metadata for discovery, configuration, and channels.

  • Added new binding module and registered it in the parent POM.
  • Implemented security, packet/response handling, capability parsing, connection manager, handler logic, and cloud integration.
  • Provided comprehensive unit tests and updated thing-types, i18n, and addon metadata.

Reviewed Changes

Copilot reviewed 46 out of 46 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
bundles/pom.xml Register org.openhab.binding.mideaac module
src/main/java/.../internal Add core binding implementation (handler, security, parser, packet, response, energy)
src/test/java/.../internal Add unit tests for security, parser, response, energy, discovery, cloud, configuration
src/main/resources/OH-INF/thing Define thing-types (channels, configuration)
src/main/resources/OH-INF/i18n Provide localization properties
src/main/resources/OH-INF/addon Add addon metadata for discovery and binding
Comments suppressed due to low confidence (2)

bundles/org.openhab.binding.mideaac/src/main/resources/OH-INF/thing/thing-types.xml:275

  • The pattern="%d%%" implies a percentage but this channel reports energy in kWh; update to a more appropriate numeric or unit-aware pattern (e.g., %.2f %unit%).
		<state readOnly="true" pattern="%d%%"/>

bundles/org.openhab.binding.mideaac/src/test/java/org/openhab/binding/mideaac/internal/handler/capabilities/CapabilityParserTest.java:152

  • [nitpick] Method name testParseWithtemperature does not follow camelCase; rename to testParseWithTemperature for consistency.
    void testParseWithtemperature() {

@apella12 apella12 force-pushed the separate-connection-manager branch 2 times, most recently from 421f838 to 6b575fd Compare July 10, 2025 00:14
@apella12
Copy link
Contributor Author

apella12 commented Jul 15, 2025

@lsiepel I didn't see your reopening comment. Must not have been notified (or thought it was related to my ZUI nofications)...

To recap; you wrote code to separate the connection manager and the MideaAC handler and I got it working again and addressed all the comments from February 21 and before. Since then I extracted several features from the HA version (and with the help of Copilot in VSC converted them to java). Also there have been a couple of new users of the forum version that had new messages that I incorporated using some Lua code references. Also because of the new features, reworked some part of the code. All that is complete now, but the binding is 25% longer. I was just making a final pass to ensure the ReadMe matched with the additional capabilities.

Added capability follow-up command and energy polling, command and reporting. Streamlined response() coding between version 2 and 3. Eliminated alternate target temp for now.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Add energy Polling Refresh, convert frequency to minutes. Edits for clarity

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Improve config descriptions and inline documentation

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Correct LED command (misread python byte) and change energy polling, even when device is off.  There is slight wattage when off to capture.
Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Introduces a new 'target humidity' channel and associated logic for setting and handling target humidity in dry mode. Adds handling for unsolicited humidity reports (0xA0), updates the command and response processing, extends the callback interface, and provides tests for the new functionality. Updates i18n and thing-type definitions to reflect the new channel.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Replaces 'target-humidity' with 'maximum-humidity' channel and adds 'filter-status' channel for Midea AC binding. Implements handling for new unsolicited temperature (0xA1) and humidity (0xA0, 0xC1) responses, updates command and response processing, and extends tests for new features. Updates documentation and i18n resources to reflect these changes.
Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Improved documentation in README and JavaDoc comments, clarified terminology (e.g., 'Maximum Humidity'), and updated test method naming for consistency. Fixed CRC8 calculation logic for correctness. Updated thing-types.xml to use correct state patterns for energy channels. Removed outdated example from README and added clarifying notes about channel support.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Minor cleanups of Temperature response and energy formats.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Update pom to 5.1

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Saw that there was a project to add tags to channels, so tried to follow examples from other bindings.  Don't have sematic model deployed, so wanted to add to the review process.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Assigned @apella12 as the code owner for /bundles/org.openhab.binding.mideaac/ in the CODEOWNERS file.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
@apella12
Copy link
Contributor Author

@lsiepel Since you are busy with the zwave-js, possibly someone else can review this. Coming up on 1 year anniversary.

Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry i had you waiting this long. I got distracted many times and needed some focus time to finish this review.
Finished all files. The handler might need some refactoring to create logical units that do a strict amount of work. especially around the initialize method and how it is called from other places.

Anyway, i think that depending on the follow-up there might be one more review, but as i have covered everything, it will not take as long as before.

Comment on lines 231 to 232
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING,
"Configuration missing, discovery needed. Discovering...");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use i18n custom keys when setting the thing state. This would make it possible to add translations.
For reference: https://next.openhab.org/docs/developer/utils/i18n.html#using-custom-keys

(applies to all occurences of updateStatus with a thingstatusdetail)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be fixed

Copy link
Contributor Author

@apella12 apella12 Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check. I have run mvn i18n:generate-default-translations -pl :org.openhab.binding.mideaac, but need to manually add the thing status details in the MideaACHandler to that file? First follow-up question, what about when the text is e.getMessage() which apparently could be null?

Second followup question what about duplicates with different messages? Do I need to massage them to be different?

# thing status descriptions

unknown.configuration_pending = Configuration not valid.
unknown.configuration_pending = Configuration missing, discovery needed. Discovering...
offline.configuration_error = Discovery failure. Check IP Address.
offline.configuration_error = Invalid MideaAC config. Check IP Address.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They keys are custom. So you are also able to use

offline.configuration_error_discovery are whatever you think is right. Obvously the key in the properties file needs to match the key in the updatestate string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have this sorted out. With the limited slate of states and descriptions did some consolidation and removed some unnecessary ones. I have assumed that e.getMessage() override the content in the i18n.

Renames energy-related channels (kilowatt-hours, amperes, watts) to energy-consumption, current-draw, and power-consumption across code, documentation, and UI resources for clarity. Refactors hex string conversion to use HexUtils from openHAB core, removing redundant methods from Utils. Improves error handling and introduces LoginFailedException for cloud login failures. Updates related tests and documentation to match new channel names. End of day WIP

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A follow up to the previous fixes.

Comment on lines 231 to 232
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING,
"Configuration missing, discovery needed. Discovering...");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be fixed

Added 'Advanced' column to README and marked advanced parameters in thing-types.xml. Changed keyTokenUpdate unit from days to hours and updated related labels, descriptions, and scheduling logic. Improved MideaACHandler to run discovery and cloud token/key retrieval asynchronously, updating thing status to UNKNOWN during pending operations. Updated i18n strings for clarity and consistency. Changed cloud login error logging from warn to debug.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Refined configuration parameter validation and error messaging for MideaAC binding. Updated default AC version to 3, clarified keyTokenUpdate interval, improved asynchronous device/cloud parameter retrieval, and enhanced connection error handling. Updated documentation and i18n resources for clearer user guidance.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think almost all comments are addressed, my main concern is the initialize method.
The openHAB model seems stable, that is one of the most important parts.

*
*/
@Override
public void initialize() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This initialize method needs some refactoring. I'm happy to help, but you should also need to understand what is going on here.

The initialize() method currently performs multiple responsibilities in one place:

  • Validating configuration
  • Attempting discovery or token/key retrieval
  • Establishing device communication
  • Fetching capabilities
  • Starting scheduled background tasks

This makes the method long and a bit difficult to follow. The logic is solid, but readability and maintainability can be improved by splitting the flow into smaller, clearly named helper methods.

Together with early returns the method would be short, straight forward and simple to adapt to prevent multiple status updates. in a row.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH last time you helped I almost decided to give up.
All these things need to be done and with the async threads it is happening fast.
I'd like to hold on this for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Íf i have time in the next days i'll create a PR against your branch. It is mainly re-ordering the code, so i guess this won;t be difficult without many device details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I enhanced the documentation in the code to hopefully avoid this, but whatever.

Copy link
Contributor

@lsiepel lsiepel Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created the PR here: apella12#2

Please test and see if all is still working as expected, if so, merge it and we can finish this PR.

Copy link
Contributor Author

@apella12 apella12 Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran some tests to exercise the initialization. Seems to work as before. (Couldn't resist, could you?)
Edit; Personally, I prefer grouped code as easier to follow, rather than having to jump around to find the linked methods. (Ok this is false, now where do I find what happens next?) Also about 100 more lines.

Comment on lines 231 to 232
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING,
"Configuration missing, discovery needed. Discovering...");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They keys are custom. So you are also able to use

offline.configuration_error_discovery are whatever you think is right. Obvously the key in the properties file needs to match the key in the updatestate string.

@apella12
Copy link
Contributor Author

apella12 commented Nov 4, 2025

I'll have to tackle the i18n tomorrow. Thanks

Refactored MideaACHandler initialization to clarify discovery and token/key retrieval steps, using more specific status messages and i18n keys. Updated i18n properties for granular error reporting. Marked 'timeout' and 'version' parameters as advanced in thing-types.xml and set version default to 3. Updated README to reflect 'timeout' as advanced.

Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com>
@lsiepel lsiepel changed the title [mideaac] Initial contribution- second try [mideaac] Initial contribution Nov 5, 2025
Signed-off-by: Leo Siepel <leosiepel@gmail.com>
@lsiepel
Copy link
Contributor

lsiepel commented Nov 6, 2025

I think we are ready. @apella12 do you need some additional time to test / verify different scenario's after latest changes?

Copy link
Contributor

@lsiepel lsiepel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM

@apella12
Copy link
Contributor Author

apella12 commented Nov 6, 2025

I have the latest version running. No more testing really needed IMO. Also, the underlying code looked the same, materially, just dispersed around the MideaACHandler class so the initialize() just had method calls. Thanks for approving !

@lsiepel
Copy link
Contributor

lsiepel commented Nov 6, 2025

o is here.
I’d like to put this out for new

The thingstatus handling did change a bit but the logic itself was not changed as that was solid. Anyway.

Now, you could add the binding's logo to the openHAB website. See https://www.openhab.org/docs/developer/addons/#add-your-add-on-s-logo-to-the-openhab-website-and-the-ui

@lsiepel lsiepel merged commit bd09a52 into openhab:main Nov 6, 2025
2 checks passed
@lsiepel lsiepel added this to the 5.1 milestone Nov 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new binding If someone has started to work on a binding. For a new binding PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants