Detect power change event / UPS state
-
Hi! I want to detect when the system is on
UPS
or just power state changes.Something like this:
I tried to detect it using
GetSystemPowerStatus
function:Code:
SYSTEM_POWER_STATUS powerStatus; bool powerStatusRes = GetSystemPowerStatus(&powerStatus); switch (powerStatus.ACLineStatus) { case 0: std::cout << "Offline" << std::endl; break; case 1: std::cout << "Online" << std::endl; break; case 255: std::cout << "Unknown status" << std::endl; default: std::cout << "Failed to detect the status" << std::endl; } switch (powerStatus.BatteryFlag) { case 1: std::cout << "High — the battery capacity is at more than 66 percent" << std::endl; break; case 2: std::cout << "Low — the battery capacity is at less than 33 percent" << std::endl; break; case 4: std::cout << "Critical — the battery capacity is at less than five percent" << std::endl; break; case 8: std::cout << "Charging" << std::endl; break; case 128: std::cout << "No system battery" << std::endl; break; case 255: std::cout << "Unknown status—unable to read the battery flag information" << std::endl; break; default: std::cout << "Failed to detect the battery flag" << std::endl; }
But it returns
powerStatus.ACLineStatus
forUPS
orAC
asOnline
and forpowerStatus.BatteryFlag
-No system battery
.Also I have tried to detect the
UPS
usingGetPwrCapabilities
function:Code:
SYSTEM_POWER_CAPABILITIES SysPowerCapabilities = {0}; if (!GetPwrCapabilities(&SysPowerCapabilities)){ std::cout << "Failed to get System Power information!" << std::endl; } if (SysPowerCapabilities.UpsPresent) { std::cout << "UPS found" << std::endl; } else { std::cout << "UPS not found" << std::endl; }
It returns -
UPS not found
(driver is not available for thisUPS
model).Now I'm trying to detect power changes by using the
Qt nativeEvent
function:bool Test::nativeEvent(const QByteArray &eventType, void *message, long *result) { Q_UNUSED(result); Q_UNUSED(eventType); MSG *msg = static_cast<MSG*>(message); if (msg->message == WM_POWERBROADCAST && msg->wParam == PBT_APMPOWERSTATUSCHANGE) { qDebug() << "Power changed!!!"; } return false; }
But nothing is printed to the console. Any ideas how to detect it? Thanks.
-
Hi,
If I understand correctly, you don't have the driver for your UPS. How can you expect Qt to catch any related events if your system can't handle the hardware ?
-
The best would be to ask the authors of
ViewPower
for that ;) -
There are likely generic APIs that the device has to answer to. Like you already did. They may be doing some polling.
-
@Cobra91151 so now you need to find the documentation for the UPS. It should explain how to control it.
-
No tech. documentation is available for this
UPS
. But I got some values from the net:0x00840010 = UPS 0x00840012 = Battery 0x00840030 = Voltage 0x00840040 = ConfigVoltage 0x0084001a = Input 0x0084005a = AudibleAlarmControl 0x00840002 = PresentStatus 0x00850044 = Charging 0x00850045 = Discharging 0x008500d0 = ACPresent
But these values could be different for my
UPS
model.Also I succeeded with connecting to the
UPS
usb:Code:
QString devicePath = "\\\\?\\HID#VID_...."; HANDLE fileHandle = CreateFileA(devicePath.toStdString().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (fileHandle != INVALID_HANDLE_VALUE) { std::cout << "Success. Device opened for reading..." << std::endl; OVERLAPPED overlapped = {}; uint8_t readBuffer[1024]; BOOL readDeviceRes = ReadFileEx(fileHandle, (LPVOID)readBuffer, sizeof(readBuffer), &overlapped, readCompleted); if (readDeviceRes) { std::cout << "Success..." << std::endl; } else { std::cout << "Failed..." << std::endl; } } else { std::cout << "Failed to open device for reading!" << std::endl; } CloseHandle(fileHandle); void CALLBACK readCompleted(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { std::cout << "Test... " << dwNumberOfBytesTransfered << std::endl; }
When I start the app, it displays:
Success. Device opened for reading...
Success...But
ViewPower
app displays thatUPS
connection has been lost, when I close my app, then theUPS
connection has been established. This means that they also read theUPS
data from aUSB
. Now I need to figure out how to get these values, read bytes. -
I have found that I need to use the
HID API
to get some values for theUPS
.Updated code:
QString devicePath = "\\\\?\\HID#VID_...."; HANDLE fileHandle = CreateFileA(devicePath.toStdString().c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (fileHandle != INVALID_HANDLE_VALUE) { std::cout << "Success. Device opened for reading..." << std::endl; PHIDP_PREPARSED_DATA preparsedData; HIDP_CAPS capabilities; HIDD_ATTRIBUTES attributes; BOOL hidPreparsedRes = HidD_GetPreparsedData(fileHandle, &preparsedData); if (hidPreparsedRes) { if (HidD_GetAttributes(fileHandle, &attributes)) { std::cout << "Product ID: " << attributes.ProductID << std::endl; std::cout << "Size: " << attributes.Size << std::endl; std::cout << "Vendor ID: " << attributes.VendorID << std::endl; std::cout << "Version number: " << attributes.VersionNumber << std::endl; if (HidP_GetCaps(preparsedData, &capabilities) == HIDP_STATUS_SUCCESS) { std::cout << "Caps: " << capabilities.NumberOutputValueCaps << std::endl; } else { std::cout << "Failed to return HID capabilities!" << std::endl; } } else { std::cout << "Failed to get HID attributes" << std::endl; } std::cout << getLastErrorAsString() << std::endl; } else { std::cout << "Failed to get preparsed data!" << std::endl; } HidD_FreePreparsedData(preparsedData); } else { std::cout << "Failed to open device for reading!" << std::endl; } CloseHandle(fileHandle);
So now, it returns:
Success. Device opened for reading...
Product ID: 20833
Size: 12
Vendor ID: 1637
Version number: 2
Caps: 1HIDP_CAPS
structure has a lot of different values, the question is how to convert them toUPS
values to check for power changes/UPS
status? Thanks.