Skip to content

Modbus driver for Huawei UPS2000/2000A (1kVA-3kVA)#954

Merged
jimklimov merged 6 commits intonetworkupstools:masterfrom
biergaizi:ups2000
Nov 7, 2021
Merged

Modbus driver for Huawei UPS2000/2000A (1kVA-3kVA)#954
jimklimov merged 6 commits intonetworkupstools:masterfrom
biergaizi:ups2000

Conversation

@biergaizi
Copy link
Copy Markdown
Contributor

@biergaizi biergaizi commented Jan 3, 2021

I recently purchased a Huawei UPS2000 for my server, but the vendor only provided a Windows management program. The program is heavy, it's written in Java that comes with a whole web server and a MySQL database, and it goes without saying that it could not be used in other operating systems - and they want to sell people an SNMP adapter card for that, which would make the UPS to be as expensive as other competing vendors. No thanks...

Fortunately, documentation is publicly available. I reasoned that it would be a waste of effort if it remains unpublished for my private use - implementing it as a NUT driver and upstreaming the driver could benefit others, thus I'm now submitting a Pull Request.

This is only an initial draft of Huawei UPS2000 (1kVA-3kVA) driver on the RS-232 interface. This driver is still a work-in-progress, so far only voltage, frequency, current, power, and temperature monitoring is implemented (I think submitting it right now is helpful to get some useful feedback), I plan to also implement UPS status flag and battery monitoring in the following day, and also to do some coding style fixes.

Notably, I had to work around a significant technical problem. The UPS uses a Modbus-based serial protocol, and right now in NUT, Modbus is already supported via libmodbus. However, libmodbus has a serious technical limitation - it only supports register reads and writes. In this driver, it needs to read device identification information to ensures that it has been hooked up to the correct UPS - which is unsupported by libmodbus. Worse, although libmodmus supports sending custom commands via modbus_send_raw_request(), but modbus_receive_confirmation() assumes the response message is formatted in a certain way with a length in the header - which is not true for our purpose - it simply stops reading in the middle. To add insult to injury, libmodbus does not provide any low-level public API for us to receive the raw message from the serial device. Thus, implementing device identification is literally impossible in libmodbus.

To solve the problem, I devised the following workaround:

  1. Open the serial port via ser_open()
  2. Open the same serial port via libmodbus.
  3. Construct a Modbus device identification message manually via ser_send_buf() and ser_get_buf(), and manually parse the response. Also, the CRC-16 verification code has to be copied and pasted into the driver.
  4. After the device identification sequence has been completed, sending and receiving normal Modbus registers reads via libmodbus as usual. Because ser_*() functions are never used anymore at this point, it's safe to do so.

Other than that, the rest of the implementation is trivial. See the code comments in the patch for more technical details.

Your code review is appreciated, thanks for your time.

Signed-off-by: Yifeng Li <tomli@tomli.me>

MAINTAINER NOTE: Issues #1066 and #1017 provide many details about this device series

@lgtm-com

This comment has been minimized.

Comment thread drivers/huawei-ups2000.c Outdated
@lgtm-com

This comment has been minimized.

@biergaizi biergaizi changed the title [WIP] RS-232 driver for Huawei UPS2000 (1kVA-3kVA) [WIP] RS-232 driver for Huawei UPS2000/2000A (1kVA-3kVA) Jan 4, 2021
@jimklimov jimklimov requested review from aquette, clepple and zykh January 4, 2021 17:15
@biergaizi biergaizi force-pushed the ups2000 branch 2 times, most recently from 38f2990 to 99b9287 Compare January 4, 2021 19:46
Copy link
Copy Markdown
Member

@aquette aquette left a comment

Choose a reason for hiding this comment

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

Lgtm, apart maybe from the go-to. But no big deal

@biergaizi
Copy link
Copy Markdown
Contributor Author

@aquette I just eliminated goto in the latest commit - it was purely coincidental, the goto was simply no longer needed after some logic reorganization for status_set() implementation.

@biergaizi biergaizi force-pushed the ups2000 branch 3 times, most recently from 417ac99 to ab145ff Compare January 6, 2021 07:55
@biergaizi
Copy link
Copy Markdown
Contributor Author

I just implemented status and alarm reporting. The driver is almost complete.

@lgtm-com

This comment has been minimized.

@biergaizi
Copy link
Copy Markdown
Contributor Author

biergaizi commented Jan 16, 2021

I must have triggered a bug in the LGTM.com static analyzer. It says

uint16_t val;
...
if (val != 0 || val != 1)
/* Alert: Comparison is always true because val <= 0. */

It's in fact a real bug, the || should be &&, but this alert is obviously nonsense. I wonder if someone at LGTM.com mistyped assert uint16_t >= 0 as assert uint16_t <= 0 in its ruleset.

@biergaizi biergaizi force-pushed the ups2000 branch 12 times, most recently from 9a20737 to a231523 Compare January 24, 2021 01:07
@biergaizi biergaizi force-pushed the ups2000 branch 2 times, most recently from dcbd245 to 98927f6 Compare September 22, 2021 07:10
@biergaizi biergaizi changed the title [WIP] RS-232 (modbus) driver for Huawei UPS2000/2000A (1kVA-3kVA) RS-232 (modbus) driver for Huawei UPS2000/2000A (1kVA-3kVA) Sep 22, 2021
@biergaizi
Copy link
Copy Markdown
Contributor Author

It's ready for a final review. The driver may still have some sharp edges, but this should be good enough for a DRV_EXPERIMENTAL. -;)

@biergaizi biergaizi force-pushed the ups2000 branch 2 times, most recently from dc91b55 to 46c5668 Compare September 22, 2021 08:07
@biergaizi biergaizi force-pushed the ups2000 branch 2 times, most recently from 0441153 to 9a11129 Compare September 23, 2021 00:44
@biergaizi
Copy link
Copy Markdown
Contributor Author

biergaizi commented Sep 23, 2021

Please do not merge the PR yet. I just realized the device driver for the MaxLinear RX21V1410 USB chip has been upstreamed since Linux 5.13, just shortly after I finished the initial driver. It means the driver should also support USB by now. I need to do some retests, and if it really works, update the code comments and documentations. On the other hand, no code change is necessary, it's strictly a kernel update, code reviews are still free to proceed.

This commit implements a Modbus driver for Huawei UPS2000
(1kVA-3kVA) series UPS units using the USB or RS-232 interface
(USB is only support on Linux 5.12+ via the "xr_serial" kernel
module), with support for power and battery status monitoring,
alarm reporting, RW variables, and instant commands for battery
selftest, buzzer, shutdown, restart, and bypass control.

Signed-off-by: Yifeng Li <tomli@tomli.me>
Signed-off-by: Yifeng Li <tomli@tomli.me>
Signed-off-by: Yifeng Li <tomli@tomli.me>
Signed-off-by: Yifeng Li <tomli@tomli.me>
@biergaizi biergaizi changed the title RS-232 (modbus) driver for Huawei UPS2000/2000A (1kVA-3kVA) Modbus driver for Huawei UPS2000/2000A (1kVA-3kVA) Sep 24, 2021
@biergaizi
Copy link
Copy Markdown
Contributor Author

biergaizi commented Sep 24, 2021

USB support has been confirmed on Linux 5.12 and newer kernels. Code comments and documentation has been updated. It's the final version of this pull request, ready for review.

@biergaizi
Copy link
Copy Markdown
Contributor Author

Bump. This PR is merge-ready since last week.

Copy link
Copy Markdown
Member

@jimklimov jimklimov left a comment

Choose a reason for hiding this comment

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

Sorry it took a while to rectify the NUT CI side as well to get to the PRs in queue, great thanks for your contribution and patience!

Made the `configure` example a bit friendlier for copy-pasting.
@jimklimov jimklimov added the ready / gonna merge The PR is in final cycles leading to merge unless someone logs an objection before we hit the button label Nov 7, 2021
@jimklimov jimklimov merged commit 51ab4de into networkupstools:master Nov 7, 2021
@jimklimov jimklimov added modbus and removed ready / gonna merge The PR is in final cycles leading to merge unless someone logs an objection before we hit the button labels Nov 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants