myTselection / telenet_telemeter

Telenet Telemeter Home Assistant custom component HACS for Belgian ISP and mobile phone network traffic.
MIT License
30 stars 6 forks source link

Telenet: multiple internet subscriptions (abonnementen) - the data of only 1 subscription is shown #45

Closed PVanhevel closed 1 month ago

PVanhevel commented 8 months ago

When one has multiple subscriptions e.g. 1 modem at the main residence and 1 modem at a secondary residence, only the data of 1 internet subscription are available. The data of the mobile services on the other hand, are available for both subscriptions.

myTselection commented 8 months ago

I don't have such account with multiple subscriptions. If you could share the (annonimzed) data shown within the attribute telemeter_json I can take a look to support this.

PVanhevel commented 8 months ago

internetProductDetails = session.productSubscriptions("INTERNET")

internetProductDetails[0] = {'activationDate': 'xxxxxxxxxxxxxx', 'addressId': '9999999999999999999', 'identifier': '**', 'label': 'All-Internet / **', 'locationId': '9999999999999999999', 'status': 'Active', 'productType': 'internet', 'internetType': 'FUP', 'specurl': 'https://api.prd.telenet.be/omapi/public/product/INTF0200', 'id': '9999999999999999999', 'useSpecurl': True, 'hasVoiceMail': False}

internetProductDetails[1] = {'activationDate': 'xxxxxxxxxxxxxx', 'addressId': '9999999999999999999', 'identifier': '**', 'label': 'WIGO Home S / WIGOHOMES_9999999', 'locationId': '9999999999999999999', 'status': 'Active', 'productType': 'bundle', 'internetType': 'CAP', 'bundleIdentifier': 'WIGOHOMES_9999999', 'specurl': 'https://api.prd.telenet.be/omapi/public/product/WIGO0001', 'id': '9999999999999999999', 'useSpecurl': True, 'hasVoiceMail': False, 'bundleType': 'WIGO'}

Only internetProductDetails[0] appears in HA.

PVanhevel commented 8 months ago

planinfo = session.planInfo() list size = 5

planinfo[0] = {'activationDate': 'xxxxxxxxxx ', 'addressId': '99999999999999', 'identifier': '****', 'label': 'All-Internet / ****', 'locationId': '99999999999999999', 'status': 'Active', 'productType': 'internet', 'isDataOnlyPlan': False, 'specurl': 'https://api.prd.telenet.be/omapi/public/product/INTF0200', 'id': '99999999999999', 'useSpecurl': False, 'hasVoiceMail': False, 'hasActiveMyBill': False}

...

planinfo[2] = {'activationDate': xxxxxxxxxxxxx, 'addressId': '999999999999999', 'identifier': 'WIGOHOMES_99999999, 'label': 'WIGO Home S / WIGOHOMES_999999999', 'locationId': '99999999999999999999', 'status': 'Active', 'productType': 'bundle', 'isDataOnlyPlan': False, 'products': [{'identifier': 99999999', 'productType': 'telephone', 'isDataOnlyLine': False}, {'identifier': '**', 'productType': 'internet', 'isDataOnlyLine': False}, {'identifier': 'DTV99999999', 'productType': 'dtv', 'isDataOnlyLine': False}], 'specurl': 'https://api.prd.telenet.be/omapi/public/product/WIGO0001', 'bundleFamily': 'WIGO', 'id': 9999999999999999', 'useSpecurl': False, 'hasVoiceMail': False, 'hasActiveMyBill': False}

...

PVanhevel commented 8 months ago

"If you could share the (anonymized) data shown within the attribute telemeter_json I can take a look to support this."

As there is no sensor for internetProductDetails[1] or planinfo[2], there is no relevant attribute telemeter_json.

PVanhevel commented 3 months ago

planInfo = session.planInfo() planInfo.reverse() productIdentifier = productIdentifiers[1] _telemeter = session.productUsage("internet", productIdentifier, startDate, endDate) print(_telemeter) {'internet': {'category': 'CAP', 'specurl': 'https://api.prd.telenet.be/omapi/public/product/WIGO0001', 'daysUntil': '24', 'validity': '2024-09-03T12:00:00.000Z', 'allocatedUsage': {'units': 200.0, 'usedUnits': 37.86, 'remainingUnits': 162.14, 'unitType': 'GB', 'usedPercentage': '18.00', 'lastUsageDate': '2024-08-10T09:43:00'}, 'extendedUsage': {'eligibleToBuy': True, 'volumeBlocks': '0', 'volume': 0, 'unit': 'GB', 'price': '0.00', 'currency': 'EUR'}, 'totalUsage': {'units': 37.86, 'unitType': 'GB', 'lastUsageDate': '2024-08-10T09:43:00'}, 'peakUsage': {'usedUnits': 0}}}

Actually I am only interested in usedPercentage = int(_telemeter["internet"]["allocatedUsage"]["usedPercentage"][:2]) usedPeriod = int((1 - int(_telemeter["internet"]["daysUntil"]) / 365.25 12) 100)

myTselection commented 3 months ago

I need a generic approach / rule to extract the data: if there are multiple internetProductDetails product types should I use bundle instead of internet?

PVanhevel commented 3 months ago
def productSubscriptions(self, productType):
    response = self.callTelenet(f"https://api.prd.telenet.be/ocapi/public/api/product-service/v1/product-subscriptions? 
            producttypes={productType}", "productSubscriptions")
    # return response.json()
    return response

session = TelenetSession()
session.login(CONF_USERNAME, CONF_PASSWORD)
internetProductDetails = session.productSubscriptions("INTERNET")

[ { "activationDate" : "2023-03-11T00:00", "addressId" : "9999999999999999", "identifier" : "xxxxxx", "label" : "All-Internet / xxxxx", "locationId" : "99999999999", "status" : "Active", "productType" : "internet", "internetType" : "FUP", "specurl" : "https://api.prd.telenet.be/omapi/public/product/INTF0200", "id" : "99999999999", "useSpecurl" : true, "hasVoiceMail" : false }, { "activationDate" : "2020-02-07T00:00", "addressId" : "999999999999", "identifier" : "yyyyyyyy", "label" : "WIGO Home S / WIGOHOMES_44714708", "locationId" : "9999999999", "status" : "Active", "productType" : "bundle", "internetType" : "CAP", "bundleIdentifier" : "WIGOHOMES_999999999", "specurl" : "https://api.prd.telenet.be/omapi/public/product/WIGO0001", "id" : "99999999999", "useSpecurl" : true, "hasVoiceMail" : false, "bundleType" : "WIGO" } ]

I am only interested in the product with "productType" == "bundle".

myTselection commented 1 month ago

if bundle is found, it will be used as of R1.7.0. Could you please validate, as I don't have a bundle I couldn't validate all cases.

PVanhevel commented 1 month ago

Tried R1.7.0 on a second HA computer: only switch.telenet_telemeter_wifi appeared.

I'm still using a modified R1.6.1 on my main HA installation, to get the attributes of my WIGO bundle.

myTselection commented 1 month ago

can you share your fix? I'll try to integrate it..

PVanhevel commented 1 month ago

I think I only added planInfo.reverse() to sensor.py as I am only interested in the data from the second of my 2 productSubscriptions.

planInfo = await self._hass.async_add_executor_job(lambda: self._session.planInfo()) planInfo.reverse()

myTselection commented 1 month ago

would you be able to share the logs of 1.7.0? I only changed in there to fetch the 'bundle' subscription instead of 'internet' if a bundle is available...

PVanhevel commented 1 month ago

1.7.0 log:

Traceback (most recent call last): File "/config/custom_components/telenet_telemeter/utils.py", line 81, in callTelenet assert response.status_code == expectedStatusCode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 361, in _async_setup_platform await asyncio.shield(awaitable) File "/config/custom_components/telenet_telemeter/sensor.py", line 119, in async_setup_entry await dry_setup(hass, config, async_add_devices) File "/config/custom_components/telenet_telemeter/sensor.py", line 52, in dry_setup await data_internet._forced_update() File "/config/custom_components/telenet_telemeter/sensor.py", line 188, in _forced_update billcycles = await self._hass.async_add_executor_job(lambda: self._session.billCycles("internet", productIdentifier)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/telenet_telemeter/sensor.py", line 188, in billcycles = await self._hass.async_add_executor_job(lambda: self._session.billCycles("internet", productIdentifier)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/telenet_telemeter/utils.py", line 177, in billCycles response = self.callTelenet(f"https://api.prd.telenet.be/ocapi/public/api/billing-service/v1/account/products/{productIdentifier}/billcycle-details?producttype={productType}&count=3","billCycles") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/telenet_telemeter/utils.py", line 103, in callTelenet assert response.status_code == expectedStatusCode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError 2024-09-28 18:06:18.460 ERROR (SyncWorker_4) [custom_components.telenet_telemeter.utils] callTelenet failed, trying once more: 2024-09-28 18:06:18.516 ERROR (MainThread) [homeassistant.components.sensor] Error while setting up telenet_telemeter platform for sensor Traceback (most recent call last): File "/config/custom_components/telenet_telemeter/utils.py", line 81, in callTelenet assert response.status_code == expectedStatusCode ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AssertionError

myTselection commented 1 month ago

Would you be able to test R1.7.1 with debug logging? I added extra log output to better understand the data structures of the bundled subscription. You may also share these by mail if you'd prefer not to post the logs here publicly. Email is mytselection[at]gmail.com

myTselection commented 1 month ago

thx for reporting! I found some family member with a bundle subscription so I could test and fix these flows now myself, I hope it's now all fixed as of R1.8.1.