Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

blazer_usb:how display battery.runtime on NUT #2389

Open
skokole opened this issue Apr 8, 2024 · 9 comments
Open

blazer_usb:how display battery.runtime on NUT #2389

skokole opened this issue Apr 8, 2024 · 9 comments
Assignees
Labels
documentation-protocol Submitted vendor-provided or user-discovered protocol information, or similar data (measurements...) NUT protocols question

Comments

@skokole
Copy link

skokole commented Apr 8, 2024

If I want to show the battery.runtime on NUT,what should I do?How should I write the communication protocol of UPS?

@jimklimov
Copy link
Member

jimklimov commented Apr 8, 2024

If the device does not serve this information (or not in a way the NUT driver can interpret it), but serves the battery voltage or charge - please explore the runtimecal config option (see man page) for "guesstimation".

@skokole
Copy link
Author

skokole commented Apr 8, 2024

If the device does not serve this information (or not in a way the NUT driver can interpret it), but serves the battery voltage or charge - please explore the config option (see man page) for "guesstimation".runtimecal

Thanks for your reply,forgive me not good at English.I`m a development of UPS,the device can show the battery runtime in our software.But,it does not show the information in NUT.What correct protocols should I use to display on NUT?

@jimklimov
Copy link
Member

jimklimov commented Apr 8, 2024

Aha, great to see vendors paying interest! :)

In NUT, we have many drivers supporting different protocols and dialects (usually with a subdriver configuration option) where applicable. These drivers translate hardware vendor protocols to a NUT common data model with naming and units of measurement, which are reported (via Unix sockets or similar) by each driver to a data server upsd running on the same system, and the numerous clients talk to the data server over TCP/IP protocol on localhost or remotely.

For USB devices, it depends on the vendor's choice of OEM firmware roots, ideally it would be standard USB HID (likely with vendor/model specific mappings - see drivers/usbhid-ups.c and many *-hid.c for illustration), most commonly there is a variant of Megatec Qx (x being a number) family handled by NUT's nutdrv_qx driver and its many subdrivers. MGE/Eaton had also a concept of SHUT (Serial HID UPS Transfer) drivers, essentially wrapping HID over serial rather than USB link medium, so that's also an option, although an unlikely one for new development.

Previously several separate drivers handled different Megatec variants, including blazer ser/usb drivers, but these are now absorbed into and deprecated in favor of nutdrv_qx which has a benefit of handling them all over both USB and serial links (which is why some vendors choose it, to handle different data ports with same firmware - the UPS USB chip being essentially a serial port dongle).

For starters, I'd suggest to read these docs:

In case of USB HID, you would likely need to provide a new mapping from USB report IDs to NUT standard data point names; possibly some data conversion helper methods if scaling etc. is needed. In case of nutdrv_qx, some *_command() and similar methods to tune the protocol, if none of the already existing ones fits, and possibly a further source file like https://github.com/networkupstools/nut/blob/master/drivers/nutdrv_qx_ablerex.c for custom logic/data/... details of the actual subdriver. In both cases, you have lots of precedent sources to look at and inspire from :)

One point of contention for hardware design (may be too late for you if the product already exists) is using USB vendorid/productid licensed from USB-IF organization and not a random mix of 0x0000, 0x0001, 0xffff which is unfortunately too common and does not really allow to tell devices apart (especially if strings for vendor/model are not populated either).

@jimklimov jimklimov added question NUT protocols documentation-protocol Submitted vendor-provided or user-discovered protocol information, or similar data (measurements...) labels Apr 8, 2024
@skokole
Copy link
Author

skokole commented Apr 23, 2024

Aha, great to see vendors paying interest! :)

In NUT, we have many drivers supporting different protocols and dialects (usually with a subdriver configuration option) where applicable. These drivers translate hardware vendor protocols to a NUT common data model with naming and units of measurement, which are reported (via Unix sockets or similar) by each driver to a data server upsd running on the same system, and the numerous clients talk to the data server over TCP/IP protocol on localhost or remotely.

For USB devices, it depends on the vendor's choice of OEM firmware roots, ideally it would be standard USB HID (likely with vendor/model specific mappings - see drivers/usbhid-ups.c and many *-hid.c for illustration), most commonly there is a variant of Megatec Qx (x being a number) family handled by NUT's nutdrv_qx driver and its many subdrivers. MGE/Eaton had also a concept of SHUT (Serial HID UPS Transfer) drivers, essentially wrapping HID over serial rather than USB link medium, so that's also an option, although an unlikely one for new development.

Previously several separate drivers handled different Megatec variants, including blazer ser/usb drivers, but these are now absorbed into and deprecated in favor of nutdrv_qx which has a benefit of handling them all over both USB and serial links (which is why some vendors choose it, to handle different data ports with same firmware - the UPS USB chip being essentially a serial port dongle).

For starters, I'd suggest to read these docs:

In case of USB HID, you would likely need to provide a new mapping from USB report IDs to NUT standard data point names; possibly some data conversion helper methods if scaling etc. is needed. In case of nutdrv_qx, some *_command() and similar methods to tune the protocol, if none of the already existing ones fits, and possibly a further source file like https://github.com/networkupstools/nut/blob/master/drivers/nutdrv_qx_ablerex.c for custom logic/data/... details of the actual subdriver. In both cases, you have lots of precedent sources to look at and inspire from :)

One point of contention for hardware design (may be too late for you if the product already exists) is using USB vendorid/productid licensed from USB-IF organization and not a random mix of 0x0000, 0x0001, 0xffff which is unfortunately too common and does not really allow to tell devices apart (especially if strings for vendor/model are not populated either).

Dear jimklimov,Thank`s for your support.

Now,NAS manufacturers have used the nutdrv_qx driver,which has resulted in some information not being available in NUT(such as ups.mfr、ups.model...).Unfortunately,many of my machines still use old drivers(blazer_usb),which I want to continue using it!The protocol I`m currently using is Voltronic Power - ‘QS’ Protocols,which can only be used on blazer_usb drivers instead of nutdrv_qx?Can I understand it this way? What can I do to get the information(such as ups.mfr、ups.model、battery.runtime) in NUT?Use the protocol of "Voltronic Power UPS Protocol - unofficial decoding work"?

@jimklimov
Copy link
Member

jimklimov commented Apr 23, 2024

Well, nutdrv_qx should also support at least some Voltronic protocols:

~/nut$ grep VERSION drivers/nutdrv_qx_voltronic*.c | grep def
drivers/nutdrv_qx_voltronic-qs-hex.c:#define VOLTRONIC_QS_HEX_VERSION "Voltronic-QS-Hex 0.10"
drivers/nutdrv_qx_voltronic-qs.c:#define VOLTRONIC_QS_VERSION "Voltronic-QS 0.09"
drivers/nutdrv_qx_voltronic.c:#define VOLTRONIC_VERSION "Voltronic 0.08"

@skokole
Copy link
Author

skokole commented Apr 24, 2024

Well, should also support at least some Voltronic protocols:nutdrv_qx

~/nut$ grep VERSION drivers/nutdrv_qx_voltronic*.c | grep def
drivers/nutdrv_qx_voltronic-qs-hex.c:#define VOLTRONIC_QS_HEX_VERSION "Voltronic-QS-Hex 0.10"
drivers/nutdrv_qx_voltronic-qs.c:#define VOLTRONIC_QS_VERSION "Voltronic-QS 0.09"
drivers/nutdrv_qx_voltronic.c:#define VOLTRONIC_VERSION "Voltronic 0.08"

Fine,I have checked the information,it seems to have used an older version - Voltronic-QS 0.07!! :(
How can I update this version(Voltronic-QS 0.07)? We need to get ups.mfr、ups.model in NUT,should I send "I" command? I have tried,but it seems didn`t work.

@jimklimov
Copy link
Member

Regarding an older version - for new development it is recommended to start from current NUT sources (fork this github repository, make a branch in your copy for the new feature, tinker there, post PRs back).

With git diff v2.8.0 drivers/*voltronic* etc. you can check locally what was changed between releases; in the recent timeframe I'd expect mostly non-functional changes due to internal refactoring (still, potential breakage => version bump). Some Qx related code base did however see quite a lot of new work over the past couple of years / minor-versioned NUT 2.8.x releases.

Regarding "which command to send", from cursory reading "I" may be correct to get information (some drivers do it and get a long string that is chopped into several sub-strings for mfr, model, serial(?) and firmware number, IIRC). Unfortunately, I am not deeply involved in Qx drivers and protocols, and mostly supervise the general architecture of the project, so am not able to answer such specific questions.

On your side, are you involved in developing the device itself (can you change the hardware/firmware; do you have specs and protocols from a team who does?) or are you trying to develop/update a driver for a "black box" device as it sits on your desk?

Actually, is the early assumption that you are in some aspect related to the "vendor" of a device correct? Or are you "just a curious user" like most of us? :)

@clepple clepple removed their assignment Apr 24, 2024
@skokole
Copy link
Author

skokole commented Apr 25, 2024

关于旧版本 - 对于新开发,建议从当前的 NUT 源代码开始(分叉这个 github 存储库,在您的副本中为新功能创建一个分支,在那里修补,将 PR 发布回来)。

使用etc.,您可以在本地检查版本之间的更改;在最近的时间范围内,我预计由于内部重构(仍然,潜在的破损 = >版本颠簸)导致的大部分非功能性更改。然而,在过去几年中,一些与 Qx 相关的代码库确实看到了相当多的新工作/次要版本的 NUT 2.8.x 版本。git diff v2.8.0 drivers/*voltronic*

关于“发送哪个命令”,粗略地阅读“I”可能是正确的获取信息(一些驱动程序这样做并得到一个长字符串,该字符串被切成 mfr、model、serial(?) 和固件编号 IIRC 的几个子字符串)。不幸的是,我没有深入参与 Qx 驱动程序和协议,并且主要监督项目的总体架构,因此我无法回答这些具体问题。

在你这边,你是否参与了设备本身的开发(你能改变硬件/固件吗?你有来自一个团队的规格和协议吗?)或者你是否正在尝试为一个“黑匣子”设备开发/更新驱动程序,因为它放在你的办公桌上?

实际上,您在某些方面与设备的“供应商”相关的早期假设是否正确?或者你和我们大多数人一样“只是一个好奇的用户”?:)

Aha,I `m indeed involved in developing the device itself ,but I just a newguy in our team. :)

Actually, we encountered a strange problem: In NUT,when we configure the blazer_usb(our UPS driver) UPS driver in ups.conf,we can get the information,such as:ups.mfr/ups.model/device.model/device.model.However,when we modify the nut ups.conf file to nutdrv_qx,these information will not be displayed in NUT(ups.mfr/ups.model/device.model/device.model).
Currently,NAS manufacturer is using version 2.7.4 of NUT to connect and obtain UPS related information,and they`re using nutdrv_qx,which will not display the information when connect our UPS(ups.mfr/ups.model/device.model/device.model).

We want to modify our code(UPS protocols or UPS driver for nutdrv_qx?) without modifying the NUT sources.Besides,I want to know that NUT wants to obtain data from UPS(like battery.runtime,ups.model...),I just need to choose the correct protocol format?

@jimklimov
Copy link
Member

Well, that gets a bit complicated then :) Usually it is HW vendors using/dictating the protocol, and programs like NUT adapting to it - I'm not sure adapting new HW releases to 8-year old software (NUT 2.7.4) is viable long-term... maybe while you would be teaching the HW/FW capabilities, the NAS vendor would just upgrade to a base OS with newer NUT packages :\ So I must worry a bit if your team's investment is placed correctly. Still, if the device would cover all bases, old and new, it would be great :)

Another aspect is to maybe work with the NAS vendors (their documentation at least) to suggest using the driver which works better for your device, at least for that older release. Usually changing docs is the most quick and cheap solution.

Finally, looking forward to the time when your customers WOULD be using newer NUT versions, be sure to test against git master branch and recent releases, so you would know the device and NUT programs work together out of the box - at least starting from some release (which you can document - e.g. "NUT v2.8.3 or newer is recommended" and that could also poke NAS vendors to update their OS).

We want to modify our code (UPS protocols or UPS driver for nutdrv_qx?) without modifying the NUT sources. Besides, I want to know that NUT wants to obtain data from UPS (like battery.runtime,ups.model...), I just need to choose the correct protocol format?

As I mentioned, unfortunately the specific protocol knowledge is not my strong side. Speaking from methodology point of view:

  • "We want to modify our code (UPS protocols or UPS driver for nutdrv_qx?) without modifying the NUT sources."
    • "Our code" for your team is about something in the UPS - e.g. the "server" side of the protocol implementation in your firmware.
    • The "UPS driver for nutdrv_qx" is part of NUT sources which you want to not modify (and if you must work with NAS'es as they are, with whatever build of NUT is deployed there and set in stone, nutdrv_qx running there is not something you can modify).
  • "Besides, I want to know that NUT wants to obtain data from UPS (like battery.runtime,ups.model...), I just need to choose the correct protocol format?"
    • Looking from especially the position of ensuring your devices work with specific old NUT releases, it would help to read the protocol spec and its implementation in NUT sources, but ultimately you would have to iterate the firmware side so it gives expected responses to those older and unmodifiable NUT drivers whose sources you have (tagged in git), to make sure the driver initialization decides which specific Megatec Qx protocol dialect to use with your device, and that the device replies to queries defined in that sub-driver for specific data points.
    • For such "reverse engineering", it can help to look at the mapping tables used in the NUT sub-drivers (example below is for current master branch; use e.g. git checkout v2.7.4 first to switch to the older release in your workspace):
$ git grep -w mfr drivers/*qx*
drivers/nutdrv_qx_ablerex.c:    { "device.mfr",                 0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_bestups.c:    { "device.mfr",                 0,      NULL,   "ID\r", "",     28,     0,      "",     0,      2,      "%s",   QX_FLAG_STATIC,         NULL,   bestups_preprocess_id_answer,   bestups_manufacturer },
drivers/nutdrv_qx_hunnox.c:     { "device.mfr",                 0,      NULL,   "FW?\r",        "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_masterguard.c:        { "device.mfr",                 0,      NULL,   "",     "",     0,      '\0',   "",     0,      0,      "Masterguard",  QX_FLAG_STATIC | QX_FLAG_ABSENT,NULL,   NULL,   NULL },
drivers/nutdrv_qx_mecer.c:      { "device.mfr",                 0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_megatec-old.c:        { "device.mfr",                 0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_megatec.c:    { "device.mfr",                 0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_mustek.c:     { "device.mfr",                 0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_voltronic.c:  { "device.mfr",         0,      NULL,   "QMF\r",        "",     2,      '(',    "",     1,      0,      "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_voltronic.c:  { "device.mfr",         0,      NULL,   "I\r",  "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },
drivers/nutdrv_qx_zinto.c:      { "device.mfr",                 0,      NULL,   "FW?\r",        "",     39,     '#',    "",     1,      15,     "%s",   QX_FLAG_STATIC | QX_FLAG_TRIM,  NULL,   NULL,   NULL },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation-protocol Submitted vendor-provided or user-discovered protocol information, or similar data (measurements...) NUT protocols question
Projects
None yet
Development

No branches or pull requests

4 participants