networkupstools / nut

The Network UPS Tools repository. UPS management protocol Informational RFC 9271 published by IETF at https://www.rfc-editor.org/info/rfc9271 Please star NUT on GitHub, this helps with sponsorships!
https://networkupstools.org/
Other
1.92k stars 345 forks source link

Proper solution for UPSes without unique serials #1273

Closed melyux closed 3 days ago

melyux commented 2 years ago

I've been struggling to get NUT working with two CyberPower UPSes that have no serials. As such, the ups.conf has no way to tell them apart now that usbhid-ups ignores the port = setting. I only discovered this silent ignoring of my nice differentiated symlinks when I did a lsof and found both driver instances accessing (and failing) the same UPS.

The usual solution to USB devices that are not uniquely distinguishable is to use udev rules to distinguish them in some way using their physical ports and setting a symlink to a specific port (e.g. /dev/ups_1, /dev/ups_2, etc.), which is the solution many use to great success in other cases. However, NUT seems to almost go out of its way to prevent this since the port setting is ignored. As such, I can only connect to one UPS per machine. If I try more, the two running drivers end up trying to connect to the same UPS and nothing works.

The master branch now allows setting the device = setting, but this isn't good enough since device number changes after reboots. A good solution would be if NUT can use something that's settable by udev, like the device name or the device symlink (aka "port"), since udev has the power to distinguish devices permanently. There have been many, many people over the years who have had this problem. Is there any way out of this?

ntwerdochlib commented 2 years ago

I too have run head on into this wall... I am trying to monitor 2 Tripplite Smart3000RM2U UPSs, but what I have found is that the driver, tripplite_usb in my case, bails out the second instance with the message "Duplicate driver instance detected! Terminating other driver!"

If there is not already a plan to address this somehow, I would offer to step up and look into it.

clepple commented 2 years ago

However, NUT seems to almost go out of its way to prevent this since the port setting is ignored.

NUT was written before libusb1, so there was no way to open a device in libusb0.1 by its port name.

A better solution would be for UPS vendors to provide unique serial numbers accessible over USB.

melyux commented 2 years ago

Software can't help and wish for hardware to do things. Sounds like the best solution is to update to libusb1.

jimklimov commented 2 years ago

Note that port names are not guaranteed persistent (at least not on all OSes) and can change as you reboot, plug things, etc.

The libusb1 support was added over time and merged last year, but I don't think the notion of ignoring usb drivers' port parameter went away - PRs welcome!

As a twist on the situation, consider that you bought a defective product - their protocol provides for a serial number but does not provide one uniquely per device. It is important for your use case. Do nag them, do post requests to fix the firmware!

On Fri, Aug 12, 2022, 20:54 melyux @.***> wrote:

Software can't help and wish for hardware to do things. Sounds like the best solution is to update to libusb1.

— Reply to this email directly, view it on GitHub https://github.com/networkupstools/nut/issues/1273#issuecomment-1213423060, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAMPTFA3D5FL4K3G6JIRIU3VY2MYFANCNFSM5NDHQH5Q . You are receiving this because you are subscribed to this thread.Message ID: @.***>

skl111 commented 1 year ago

Screenshot 2023-04-23 234831 I am experiencing this same issue setting up a 3d Printer farm where I use 1 UPS per printer.

I did some skulking around and I discovered this from lsusb -t

If support was added to nut to specify the Bus, Port, Port, Port until you get to the port the device is on, that would eliminate the need for the serial #. 2 of my cyberpower ups units are on Bus 4, Port, Port 1, Ports 3,1. which is a 4 port hub with only 2 connected and since I am not moving them around, their ports do not change. even after reboot.

ntwerdochlib commented 1 year ago

I am running a local modification that addresses this issue by allowing the code to skip devices that are already detected. I am running 2 Tripplite UPSs that do not have have serial numbers available in the USB query. I would have to check to see if I pushed these changes to a branch on github

jimklimov commented 1 year ago

@ntwerdochlib : Cheers, I believe similar work was done in master branch, see PR #1770

jimklimov commented 1 year ago

@skl111 : I can't vouch for how precisely would libusb allow to specify the paths. I think it has a way to identify a "bus" and a "device" on that bus (or "port" in some documentation, with minute differences not seen in parctice on several platforms where discussion went that deep).

Either way, it does not specify a tree but two values which I believe to logically map to an USB hub (as bus) and either its physical port (should be stable) or some logical identifier it assigned to an attached device (which potentially can change due to re-plugs of stuff). Or so I thought. In the tree view above, all device numbers happen to be unique (some devices have more than one interface), but the Bus is only reported for a root hub - which has a branch of further hubs each with its port numbers starting from 1. So the bus+device ID matching as implemented in NUT now(*) should suffice.

(*) Note: there were fixes to "device" matching on the master branch this year, no official release since then yet => see #1763 and related PRs for details. On most OSes you would need a custom NUT build for now, https://github.com/networkupstools/nut/wiki/Building-NUT-for-in%E2%80%90place-upgrades-or-non%E2%80%90disruptive-tests can help with that.

skl111 commented 1 year ago

@jimklimov thanks for the reply, lsusb uses libusb so that pr probably is accurate. I will have to take some time to compile a build for rocky 8 and debian 9 to see how well it works until and official release.

jimklimov commented 1 year ago

FYI: I'll be mostly offline till mid-May. Good luck on your quest!

skl111 commented 1 year ago

I finally got around to getting this working on debian 11 and maybe I am missing something, but this does not solve the issue as it references the device # and if that device gets removed manually or by the device itself before nut can grab it, then that # increments and its no longer valid for the config. The device being CyberPower USB connected UPS's in particular.

CyberPower Device shows connected

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 63, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

after the 2nd ups disconnected and reconnected.

/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 66, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

I saw this option allow_duplicates but based on the manual it looks like it will ignore all 7 regex options, and it works for 2 Cyberpower UPS'es when I have it added to the 2nd UPS and that stopped it from disconnecting like it did above before I added it. If I add another CyberPower UPS, then it could get them both mixed up?

skl111 commented 12 months ago

And update to this based on testing. allow_duplicates looks like it obeys the bus & dev rule, as I had the dev's at ports 6 & 7 and then when I rebooted a few times the timing was off by enough difference that nut didn't catch them when they were at 6 & 7 and they kept disconnecting and reconnecting at higher numbers.

I updated the udev rule for that series via a post in a gentoo forum about this issue to include

RUN+="/sbin/upsdrvctl stop ; /sbin/upsdrvctl start"

so it looks like

ATTR{idVendor}=="0764", ATTR{idProduct}=="0501", MODE="664", GROUP="nut", RUN+="/sbin/upsdrvctl stop ; /sbin/upsdrvctl start"

After a few reboots so far they are staying at dev 6 & 7.

I think having nut-scanner scan the ports and when it finds CyberPower UPS's, to add the usb hub port # instead of the dev # so it starts trying to attach to the UPS on that port, would bypass the need for a udev rule change.

And of course include a warning about these finicky CyberPower UPSs'

:; lsusb -tv output
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    ID 1d6b:0002 Linux Foundation 2.0 root hub
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/3p, 480M
        ID 05e3:0610 Genesys Logic, Inc. Hub
        |__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
        |__ Port 2: Dev 4, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics
            |__ Port 1: Dev 6, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
            |__ Port 2: Dev 7, If 0, Class=Human Interface Device, Driver=usbfs, 1.5M
                ID 0764:0501 Cyber Power System, Inc. CP1500 AVR UPS
        |__ Port 3: Dev 5, If 0, Class=Hub, Driver=hub/4p, 480M
            ID 214b:7250 Huasheng Electronics

UPS.conf

[Ender3Pro1UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 1 UPS"
        pollonly = "enabled"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "006"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates

[Ender3Pro2UPS]
        driver = "usbhid-ups"
        port = "auto"
        desc = "Ender 3 Pro 2 UPS"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "07"
        ###NOTMATCHED-YET###bcdDevice = "0001"
        allow_duplicates
jimklimov commented 12 months ago

Hi, just recently a PR #2054 has landed to add busport settings (also to nut-scanner discoveries) - I wonder if on your system the two UPSes would show that same bus and port (as HW topology), with possibly differing logical device numbers?

skl111 commented 12 months ago

Hi, just recently a PR has landed to add busport settings (also to nut-scanner discoveries) - I wonder if on your system the two UPSes would show that same bus and port (as HW topology), with possibly differing logical device numbers?

Thats exactly what it does, it increments the dev numbers if it doesn't get attached to, physically the same ports.

skl111 commented 12 months ago

I updated the local source and remvoed the udev rule modification as well as the device # and it looks to be working, I will monitor and update it if I do or do see any issues with it.

[Ender3Pro2UPS] driver = "usbhid-ups" port = "auto" desc = "Ender 3 Pro 2 UPS" vendorid = "0764" productid = "0501" product = "ST Series" vendor = "CPS" bus = "003"

rem device = "007"

    busport = "002"
    ###NOTMATCHED-YET###bcdDevice = "0001"
    allow_duplicates
jimklimov commented 12 months ago

Ok, so just for making a note - on the hub whose topology libusb reports for us, the busport values did differ here. Thanks!

skl111 commented 12 months ago

Ok, so just for making a note - on the hub whose topology libusb reports for us, the busport values did differ here. Thanks!

Here is the nutscanner output and I am attaching a screenshot of the lsusb -tv output. lsusb -tv 2023-09-19 040443

Scanning USB bus.
[nutdev1]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "007"
        busport = "002"
        ###NOTMATCHED-YET###bcdDevice = "0001"
[nutdev2]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0764"
        productid = "0501"
        product = "ST Series"
        vendor = "CPS"
        bus = "003"
        device = "006"
        busport = "001"
        ###NOTMATCHED-YET###bcdDevice = "0001"
jimklimov commented 11 months ago

@skl111 : Also, looking at your earlier comment:

I saw this option allow_duplicates but based on the manual it looks like it will ignore all 7 regex options

By code, I believe it should honour the regex options (if set), and just not abort the driver initialization if it has a hit but the discovered libusb device is busy - move on and find another hit. If documentation was not sufficiently clear about this, feel free to post a PR with a better understandable rephrasing - beauty is in the eyes of the beholder, I've re-read docs/man/nut_usb_addvars.txt and it seemed okay :)

jimklimov commented 3 days ago

As of NUT v2.8.2 with PR #2221 in place, it was decided that OS enumeration dependent values are too flaky for generated and written config files to rely on.

Currently nut-scanner would not promote these into configuration by default, but would print them as comments (so end-users may choose to skip or use these values):

:; ./tools/nut-scanner/nut-scanner -U
Scanning USB bus.
[nutdev-usb1]
        driver = "usbhid-ups"
        port = "auto"
        vendorid = "0463"
        productid = "FFFF"
        product = "Ellipse ECO"
        serial = "000000000"
        vendor = "EATON"
        # bus = "003"
        # device = "005"
        # busport = "002"

# WARNING: all-same character "serial" with 9 copies of '0' (0x30) reported in some devices: nutdev-usb1

More copies of the -U argument would print these values not-commented away(-UU "unlocks" bus and busport lines, -UUU also "unlocks" the device line).