Giter Club home page Giter Club logo

pyemvue's Introduction

PyEmVue

A Python Library for reading data from the Emporia Vue energy monitoring system.

The library can be invoked directly to pull back some basic info but requires your email and password to be added to a keys.json file, which is then replaced with the access tokens.

The backing API documentation can be accessed here

keys.json

{
    "username": "[email protected]",
    "password": "password"
}

Usage

Typical Example - Getting Recent Usage

This example prints out the device list and energy usage over the last minute.

#!/usr/bin/python3

import pyemvue
from pyemvue.enums import Scale, Unit

def print_recursive(usage_dict, info, depth=0):
    for gid, device in usage_dict.items():
        for channelnum, channel in device.channels.items():
            name = channel.name
            if name == 'Main':
                name = info[gid].device_name
            print('-'*depth, f'{gid} {channelnum} {name} {channel.usage} kwh')
            if channel.nested_devices:
                print_recursive(channel.nested_devices, info, depth+1)

vue = pyemvue.PyEmVue()
vue.login(username='put_username_here', password='put_password_here', token_storage_file='keys.json')

devices = vue.get_devices()
device_gids = []
device_info = {}
for device in devices:
    if not device.device_gid in device_gids:
        device_gids.append(device.device_gid)
        device_info[device.device_gid] = device
    else:
        device_info[device.device_gid].channels += device.channels

device_usage_dict = vue.get_device_list_usage(deviceGids=device_gids, instant=None, scale=Scale.MINUTE.value, unit=Unit.KWH.value)
print('device_gid channel_num name usage unit')
print_recursive(device_usage_dict, device_info)

This will print out something like:

device_gid channel_num name usage unit
 1234 1,2,3 Home 0.018625023078918456 kwh
- 2345 1,2,3 Furnace 0.0 kwh
- 2346 1,2,3 EV 0.0 kwh
 1234 1 Oven 0.0 kwh
 1234 2 Dryer 0.0 kwh
 1234 3 Water Heater 0.0 kwh
 1234 4 Kitchen 1 0.0 kwh
- 3456 1,2,3 Washer 2.0127220576742082e-06 kwh
 1234 5 Living Room 0.00031066492724719774 kwh
- 123456 1,2,3 myplug None kwh
- 123457 1,2,3 Tree None kwh
- 123458 1,2,3 Kitchen Counter 5.368702827258442e-05 kwh
 1234 6 Bar Area 0.0020457032945421006 kwh
 1234 7 Kitchen 2 0.0 kwh
 1234 8 Dishwasher 0.0002561144436730279 kwh
 1234 9 Bathroom Heater 0.0 kwh
 1234 10 Microwave 0.0 kwh
 1234 11 AC 0.0 kwh
 1234 12 Basement 0.0011743871887920825 kwh
- 123459 1,2,3 Dehumidifier 0.005342410305036585 kwh
 1234 13 Deck 0.0 kwh
 1234 14 Front Room 0.0027938466452995143 kwh
- 123450 1,2,3 Library 0.0001436362373061446 kwh
 1234 15 Office 0.004370743334687561 kwh
- 123451 1,2,3 Network 0.001209796911216301 kwh
- 123452 1,2,3 Bedroom Fan None kwh
 1234 16 Garage 0.0005456661001841227 kwh
 1234 Balance Balance 0.00037836666266123273 kwh

Log in with username/password

vue = PyEmVue()
vue.login(username='[email protected]', password='password', token_storage_file='keys.json')

token_storage_file is an optional file path where the access tokens will be written for reuse in later invocations. It will be updated whenever the tokens are automatically refreshed.

Log in with access tokens

with open('keys.json') as f:
    data = json.load(f)

vue = PyEmVue()
vue.login(id_token=data['id_token'],
    access_token=data['access_token'],
    refresh_token=data['refresh_token'],
    token_storage_file='keys.json')

Get customer details

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

customer = vue.get_customer_details()

Returns a Customer object with email address, name, customer_gid, and creation date

Get devices

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

vue.get_devices()

Returns a list of VueDevices with device information, including device_gid and list of VueDeviceChannels associated with the device. VueDeviceChannels are passed to other methods to get information for the specific channel.

Get additional device properties

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

device1 = vue.get_devices()[0]
print(device1.device_name) # prints ""
device1 = vue.populate_device_properties(device1)
print(device1.device_name) # prints "Home"

Updates and returns the passed VueDevice with additional information about the device such as the device name (as set in the app), zip code, timezone, electricity costs, etc.

Arguments

  • device: A VueDevice as returned by get_devices. Will be updated and returned.

Get usages for devices

See Typical Example above.

Gets the usage for the given devices (specified by device_gid) over the provided time scale. May need to scale it manually to convert it to a rate, eg for 1 second data kilowatt={usage in kwh/s}*3600s/1h or for 1 minute data kilowatt={usage in kwh/m}*60m/1h.

Arguments

  • deviceGids: A list of device_gid values pulled from get_devices() or a single device_gid.
  • instant: What instant of time to check, will default to now if None.
  • scale: The time scale to check the usage over.
  • unit: The unit of measurement.

Get usage over time

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

devices = vue.get_devices()

usage_over_time, start_time = vue.get_chart_usage(devices[0].channels[0], datetime.datetime.now(datetime.timezone.utc)-datetime.timedelta(days=7), datetime.datetime.now(datetime.timezone.utc), scale=Scale.DAY.value, unit=Unit.KWH.value)

print('Usage for the last seven days starting', start_time.isoformat())
for usage in usage_over_time:
    print(usage, 'kwh')

Gets the usage in the scale and unit provided over the given time range. Returns a tuple with the first element the usage list and the second the datetime that the range starts.

Arguments

  • channel: A VueDeviceChannel object, typically pulled from a VueDevice.
  • start: The start time for the time period. Defaults to now if None.
  • end: The end time for the time period. Default to now if None.
  • scale: The time scale to check the usage over.
  • unit: The unit of measurement.

Toggle outlets

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

outlets = vue.get_outlets()
for outlet in outlets:
    vue.update_outlet(outlet, on=(not outlet.outlet_on))
    # alternatively it can be set on the outlet object first
    outlet.outlet_on = not outlet.outlet_on
    outlet = vue.update_outlet(outlet)

The get_outlets call returns a list of outlets directly but it is also possible to get a full VueDevice for the outlet first through the get_devices call and access an OutletDevice through the outlet attribute off of the VueDevice (ie device.outlet).

Toggle EV Charger (EVSE)

vue = PyEmVue()
vue.login(id_token='id_token',
    access_token='access_token',
    refresh_token='refresh_token')

chargers = vue.get_chargers()
for charger in chargers:
    vue.update_charger(outlet, on=(not charger.charger_on), charge_rate=charger.max_charging_rate)
    # alternatively you can update the charger object first
    charger.charger_on = not charger.charger_on
    charger.charging_rate = 6
    charger.max_charging_rate = 16
    charger = vue.update_charger(charger)

The get_chargers call returns a list of chargers directly but it is also possible to get a full VueDevice for the charger first through the get_devices call and access a ChargerDevice through the ev_charger attribute off of the VueDevice (ie device.ev_charger).

Get Vehicles and Status (including battery charge level).

Note: this call may take an extended amount of time depending on the vehicle, and may "wake" the vehicle to check status - be mindful of call volume, and aware of 10 second timeout that will hit if the vehicle doesn't reply in time (future may want to increase that).

vehicles = vue.get_vehicles()
print('List of Vehicles')
for vehicle in vehicles:
    print(f'\t{vehicle.vehicle_gid} ({vehicle.display_name}) - {vehicle.year} {vehicle.make} {vehicle.model}')

print('List of Vehicle Statuses')
for vehicle in vehicles:
    vehicleStatus = vue.get_vehicle_status(vehicle)
    print(f'\t{vehicleStatus.vehicle_gid} {vehicleStatus.vehicle_state} - Charging: {vehicleStatus.charging_state} Battery level: {vehicleStatus.battery_level}')

Disclaimer

This project is not affiliated with or endorsed by Emporia Energy.

pyemvue's People

Contributors

druggeri avatar kennethroe avatar magico13 avatar ofields avatar tyler201 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyemvue's Issues

TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

Running python -m pyemvue keys.json, I get an exception at the end:

$ python -m pyemvue keys.json
Logged in. Authtoken follows:
...

id1 id2 VUE002 Vue2-id3
         id4 None 1,2,3 1.0
... info about my vue, and 16 circuit breaker info...

Traceback (most recent call last):   <--- error starts here
  File "/Users/raymochi/.pyenv/versions/3.6.6/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/Users/raymochi/.pyenv/versions/3.6.6/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/Users/raymochi/.pyenv/versions/3.6.6/lib/python3.6/site-packages/pyemvue/__main__.py", line 86, in <module>
    main()
  File "/Users/raymochi/.pyenv/versions/3.6.6/lib/python3.6/site-packages/pyemvue/__main__.py", line 60, in main
    print(vue.get_total_usage(devices[0].channels[0], TotalTimeFrame.MONTH.value) / 1000, 'kwh used month to date')
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

My vue2 does not have the main clamp installed (won't fit), but I do have the individual circuit breaker clamps installed.

In the Emporia app, the result for total shows 0.000 and 100% respectively. Individual circuit shows usage, but with 0%.

integration emporia_vue has state class total_increasing, but its state is negative.

The log in home assistant:

Logger: homeassistant.components.sensor.recorder
Source: components/sensor/recorder.py:331
Integration: Sensor (documentation, issues)
First occurred: June 24, 2022 at 7:05:10 PM (2 occurrences)
Last logged: June 24, 2022 at 7:05:10 PM

Entity sensor.none_123_1mon from integration emporia_vue has state class total_increasing, but its state is negative. Triggered by state -124.334 with last_updated set to 2022-06-24T22:59:59.999999+00:00. Please report it to the custom component author.
Entity sensor.none_123_1d from integration emporia_vue has state class total_increasing, but its state is negative. Triggered by state -17.883 with last_updated set to 2022-06-24T22:59:59.999999+00:00. Please report it to the custom component author.

I have solar panels, and it's possible that at 7pm they stop producing much power

Question about A/B testing vs. Emporia app

Love this project! I have a project with a home monitoring system (https://github.com/dglcinc/pivac), that includes power panel and various HVAC sources, which get collected and reformatted as JSON streams to a Signal-K server (https://github.com/SignalK/signalk-server) that saves off the metrics to InfluxDB for Grafana charting, and a third party IOS app (WilhelmSK) for visualization.

For power monitoring, I was using an ancient power panel monitor called TED5000, which had its own local webserver/database/charting and with a real-time XML feed. I grabbed the feed and reformatted as JSON for my project.

For my new EmVue, your module makes it a snap to create a JSON formatting plugin for my app (which will be saved automatically to InfluxDB for me by Signal-K. I got all the sample code working - the biggest trick was figuring out how to get the instant and scaling parameters set right. BUT - I'm still a little suspicious that I'm not getting the same data that I see if I run Emporia's app. It's in the same ballpark, but not spot on like I used to see with the TED5000 web page vs. their XML feed. For any given second, looking at kwh, I'll see about (for example) 4kwh from my PyEmVue call and 3.5kwh for the IOS app, for any given second.

Is there any way to see the API calls the Emporia app is making, or otherwise sync up my calls vs the app? Ultimately I'll stop using the app and use my monitoring solution to show both realtime and influx/grafana charting, but I want to make sure I'm synced up vs. "the real thing".

Any thoughts on how to be convinced I'm getting the same data in both the original app and my own version that's calling the APIs? Is there way I can see the API calls each version is making? I only care about second-to-second realtime, because I'll be using Influx and Grafana for the database and charting.

Thanks again for an awesome repository!

David

Unable to install package

I've tried to install on two different boxes (raspian and OSX) and both give this eror:

Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pyemvue
  Downloading https://files.pythonhosted.org/packages/0e/a7/7054fa7d3ec4bc53d8f6f866045e9d1a1d161bda3dc4eb5ed968275ed9d2/pyemvue-0.9.3.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-GlBX1M/pyemvue/setup.py", line 3, in <module>
        with open("README.md", "r") as fh:
    IOError: [Errno 2] No such file or directory: 'README.md'

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-GlBX1M/pyemvue/

Is the package missing README.md?

Documentation examples need to be improved

For the n00bs its hard to make this work.

I create a python script & your very first example fails:
Traceback (most recent call last):
File "./get_emporia.py", line 6, in
vue = pyemvue()
NameError: name 'pyemvue' is not defined

Can you provide a full first example, i.e.

#!/usr/bin/python3
import pyemvue
import json

vue = pyemvue()

so that its easier for people to get started

Issue getting instant wattage

Hi

I love this project. I have had some success getting kWH from the API but I am having issues getting instant watts (like I can in the App). Can anyone paste in a snippet of code I can use to obtain this?

Stephen

pulling past power-data on a second-by-second basis

Hello,

although I have been working with the great package pyemvue for some time now, I have not yet managed to get past power data. I know that Emporia /Amazon AWS provides second by second data only for a limited period of time. My idea was to create a script that before the end of the deletion of the record of a certain period, let's say hourly, to populate and process the secondly data at once. Just to be clear, I do not want to populate average values, but the exact measured values.

Is there someone who could help me, also with regard to the storage time in the Emporia Cloud system?

Thanks in advance!

Raphael

API change on 8/18 -> broken PyEmVue?

Hello there. First, thanks for taking the time to create this library! I ended up turning this into a Prometheus exporter, FWIW :-)

I'm curious if the API has maybe changed from underneath the library. As of Aug 18 11:24:40 Central US time, I've seen 4xx errors in logs when attempting to make calls to the API.

This is the error noticed during vue.get_devices_usage(deviceGids, None, scale=Scale.MINUTE.value, unit=Unit.KWH.value), after already logged in and with all GIDs handy (unfortunately, log is truncated):
requests.exceptions.HTTPError: 499 Client Error: for url: https://api.emporiaenergy.com/AppAPI?apiMethod=getDevicesUsage&deviceGids=46959+57265+57269+57276+57318+57318+57671+57671+58403+58403+5933

On restart of my monitoring daemon, I get a different error (exercising a different part of the API) when calling vue.get_devices()
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.emporiaenergy.com/customers/26086/devices?detailed=true&hierarchy=true

To be sure I didn't booger up something with my credentials or whatnot, I verified this does the same thing after logging in with credentials as well as API keys.

If it would be helpful, I can gather more detailed logs or header info. Based on Kevin's response recently on the Emporia forum (and I guess maybe Ted's here in the Issue tracker), I don't think Emporia is trying to lock PyEmVue out... maybe just an API format or header format change?

Missing unit of AMPS

Could you kindly add AMPS. I tried AMPS, AMP, CURRENT , CURRENTS and none seems to work. but their app does show amps so they are storing the data.

Bug in date parsing

Observed in a project I'm working on, making an issue so I can get back to this easily later and for visibility.

channel_usage_list = vue.get_recent_usage(scale=Scale.SECOND.value, unit=Unit.WATTS.value)
File "/var/task/pyemvue/pyemvue.py", line 94, in get_recent_usage
return self.get_usage_for_time_scale(now, scale, unit)[0]
File "/var/task/pyemvue/pyemvue.py", line 110, in get_usage_for_time_scale
realStart = datetime.datetime.strptime(j['start'], '%Y-%m-%dT%H:%M:%SZ')
File "/var/lang/lib/python3.7/_strptime.py", line 577, in _strptime_datetime
tt, fraction, gmtoff_fraction = _strptime(data_string, format)
File "/var/lang/lib/python3.7/_strptime.py", line 359, in _strptime
(data_string, format))
ValueError: time data '2020-07-09T17:07:24.419489Z' does not match format '%Y-%m-%dT%H:%M:%SZ'

Write a Prometheus exporter using PyEmVue

It would be very nice to take the metrics that PyEmVue can GET from the Emporia Vue cloud and present them for scraping via Prometheus. Someone may already have done this. If so, I would appreciate a link. Otherwise I can give this a shot or get someone to do it.

get_devices() Typerror: Parser must be a string not NoneType

Hi all,

I updated to latest package to solve auth issues but I am now having a date parsing issue when doing the following:

with open('keys.json') as f:
    data = json.load(f)

vue = em.PyEmVue()

token_storage_file='keys.json')
vue.login(id_token=data['idToken'],
   access_token=data['accessToken'],
   refresh_token=data['refreshToken'],
   token_storage_file='keys.json')

devices = vue.get_devices()

for device in devices:
	device = vue.populate_device_properties(device)
	print(device.device_name)

I get the following error:
File "get_report.py", line 16, in
devices = vue.get_devices()
File "/env/lib/python3.9/site-packages/pyemvue/pyemvue.py", line 59, in get_devices
devices.append(VueDevice().from_json_dictionary(dev))
File "/env/lib/python3.9/site-packages/pyemvue/device.py", line 68, in from_json_dictionary
if 'offlineSince' in con: self.offline_since = parse(con['offlineSince'])
File "env/lib/python3.9/site-packages/dateutil/parser/_parser.py", line 1374, in parse
return DEFAULTPARSER.parse(timestr, **kwargs)
File "/env/lib/python3.9/site-packages/dateutil/parser/_parser.py", line 646, in parse
res, skipped_tokens = self._parse(timestr, **kwargs)
File "env/lib/python3.9/site-packages/dateutil/parser/_parser.py", line 725, in _parse
l = _timelex.split(timestr) # Splits the timestr into tokens
File "env/lib/python3.9/site-packages/dateutil/parser/_parser.py", line 207, in split
return list(cls(s))
File "env/lib/python3.9/site-packages/dateutil/parser/_parser.py", line 75, in init
raise TypeError('Parser must be a string or character stream, not '
TypeError: Parser must be a string or character stream, not NoneType

Thanks for your help.

Link broken to api documentation on pypi.org

Your pypi project was linked to on the Emporia website forums. In the pypi project, there is a link for api documentation that is broken.

In the mobile version of the pypi page, there is no link to github. I was able to get the link by changing to desktop mode in my phone's browser. A link to github in the information you supply on that page might be beneficial for others to find you on github.

Thanks for creating this and documenting their web api. It would be nice if they would open up the device itself for LAN access.

Getting A & B phases for circuit leveling

Instead of just getting Home usage in getchart (history), can you pull the A&B side of both phases? Not sure if the data is exposed but it is there as when you do an extract from Emporia all history file show Home_1 and Home_2 instead of a single Home total.

403 forbidden

I am getting an error when I try to execute:

devices = vue.get_devices()

requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://api.emporiaenergy.com/customers/22563/devices?detailed=true&hierarchy=true

The keys.json shows the tokens have been added.

Lower resolution than 1 hour chart usage is returning 400

Hello,

I am getting a HTTPError: 400 Client Error: Bad Request for url when trying to collect 1 minute or 1 second data. The request works fine for 1Hour or greater. In the past, I was able to collect 1S data, but it seems like it hasn't been collecting that for a few months.

This is the command I am running:
usage_over_time_min, start_time_min = vue.get_chart_usage(devices[0].channels[chidx], time_now-datetime.timedelta(days=int(2)), time_now-datetime.timedelta(days=int(1)), scale='1Min', unit='KilowattHours')

And just swapping out 1Min to 1H or 1D works great. I have tried 1S, 1MIN, 1M, 1Min and it consistently returns the error shown below

HTTPError: 400 Client Error: Bad Request for url: https://api.emporiaenergy.com/AppAPI?apiMethod=getChartUsage&deviceGid=92157&channel=1,2,3&start=2022-11-19T16:00:00Z&end=2022-11-20T16:00:00Z&scale=1Min&energyUnit=KilowattHours

image

Any thoughts?

Question: Tempted to buy this device but want opinion please

I am so much tempted to buy this device to monitor electricity usage along with solar generation. And only reason holding on just because no official data access except their app. If people are happy with this library and not much issues with unofficial API then I want to throw away about $150 to try it out!

I would like to know from you who already using device and using this library to pull/capture data please share experience. I am heavily invested in automation with so many sensors/devices and very much into programming as well so in case needed tweaking I think I can do that as well.

Appreciate your time and feedback.
Great work everyone!
Thanks

Power factor

Hello,

dies the device consider Power factor, or does it ist multiply current and Voltage?

Greetings,
Hendrik

Very interesting

I am guessing you have a patched version the Emporia Energy android app which bypasses certificate issues to be able to inspect the traffic done by the app via a proxy ?

Bad Request

Hello

I've worked with the API without trouble but today's msg is:

requests.exceptions.HTTPError: 400 Client Error: Bad Request for URL: https://api.emporiaenergy.com/customers/#####/devices?detailed=true&hierarchy=true

Tha code is:

vue = PyEmVue()
vue.login(username='xxx@xxxcom', password='xxxxx')

dispositivos=vue.get_devices() (Here is the error)
for dispositivo in dispositivos:
device=vue.populate_device_properties(dispositivo)
sede=device.device_name
print(sede)

Any changes in the API maybe?

Than you

Read the Zigbee data directly

any chance you can read the zigbee data directly?
I really hate going to 'the cloud' to get my own data......
I see you also have a Home Assistant Integration. Check out Homeseer.
you could probably easily create a simple plugin.....
good luck.

sorry for using an 'issue' I did not see any other way of contacting you.

Add support for Smart Plug

I've got one on the way already and am planning on adding support for whatever features it provides. At minimum I expect that to be the ability to turn the plug on and off but if there is also data I can pull, or scheduling capabilities, then I'll want to include that as well if possible.

How to get non-energy data

I am trying to get power data by using the following line:
usage_over_time, start_time = vue.get_chart_usage(devices[0].channels[0], datetime.datetime.utcnow()-datetime.timedelta(seconds=1), datetime.datetime.utcnow(), scale=Scale.SECOND.value, unit='Kilowatt')
I think that the library does not cover power units in the enums, so I guessed this was the correct name for the API to interpret. I am not getting a response from such API, so I wonder if it is possible to get information that is not energy.

Possible API changed again ?

I made no changes on my side and see this now :

channel_usage_list = vue.get_devices_usage(deviceGids, None, scale=pyemvue.enums.Scale.SECOND.value, unit=pyemvue.enums.Unit.AMPHOURS.value)

File "c:\Python38-64\lib\site-packages\pyemvue-0.12.2-py3.8.egg\pyemvue\pyemvue.py", line 88, in get_devices_usage
File "c:\Python38-64\lib\site-packages\pyemvue-0.12.2-py3.8.egg\pyemvue\device.py", line 97, in from_json_dictionary
TypeError: argument of type 'NoneType' is not iterable

Looks like they again changed the API.. always around 4PM EST :)

devices = vue.get_devices()
Traceback (most recent call last):
File "", line 1, in
File "c:\Python38-64\lib\site-packages\pyemvue\pyemvue.py", line 59, in get_devices
devices.append(VueDevice().from_json_dictionary(dev))
File "c:\Python38-64\lib\site-packages\pyemvue\device.py", line 68, in from_json_dictionary
if 'offlineSince' in con: self.offline_since = parse(con['offlineSince'])
File "c:\Python38-64\lib\site-packages\dateutil\parser_parser.py", line 1374, in parse
return DEFAULTPARSER.parse(timestr, **kwargs)
File "c:\Python38-64\lib\site-packages\dateutil\parser_parser.py", line 646, in parse
res, skipped_tokens = self._parse(timestr, **kwargs)
File "c:\Python38-64\lib\site-packages\dateutil\parser_parser.py", line 725, in _parse
l = _timelex.split(timestr) # Splits the timestr into tokens
File "c:\Python38-64\lib\site-packages\dateutil\parser_parser.py", line 207, in split
return list(cls(s))
File "c:\Python38-64\lib\site-packages\dateutil\parser_parser.py", line 75, in init
raise TypeError('Parser must be a string or character stream, not '
TypeError: Parser must be a string or character stream, not NoneType

Examples have few typos

Awesome project! thank you very much for doing this.

The examples are using _ but should be upper case second word.

The login with tokens example should be

vue.login(id_token=data['idToken'],
access_token=data['accessToken'],
refresh_token=data['refreshToken'],
token_storage_file='keys.json')

vs id_token , access_token etc.

Thanks much!

GetDevicesUsage only returning Null

Example API call:
https://api.emporiaenergy.com/AppAPI?apiMethod=getDevicesUsage&deviceGids=1234+3456&instant={{$isoTimestamp}}&scale=1S&energyUnit=KilowattHours

returns

{
    "channelUsages": [
        {
            "deviceGid": 1234,
            "channelNum": "1,2,3",
            "usage": null
        },
        {
            "deviceGid": 3456,
            "channelNum": "1,2,3",
            "usage": null
        }
    ]
}

As a result this is breaking the home assistant integration. Most likely related to the new app update and other recent API changes. Will have to see if this call is still supported or if there's a new call that should be used for this method.

Interestingly the home screen of the app is also not displaying this info correctly, only showing historical data. Could be an issue purely on their side.

Error retrieving device usage

Per the doc, After logging in and getting tokens, I am trying this:

channel_usage_list = vue.get_devices_usage(deviceGids, None, scale=Scale.DAY.value, unit=Unit.KWH.value)

Traceback (most recent call last):
File "", line 1, in
File "/Users/ihf/opt/anaconda3/lib/python3.7/site-packages/pyemvue/pyemvue.py", line 88, in get_devices_usage
if channel: channels.append(VueDeviceChannelUsage().from_json_dictionary(channel))
File "/Users/ihf/opt/anaconda3/lib/python3.7/site-packages/pyemvue/device.py", line 97, in from_json_dictionary
if 'value' in js['usage']:
TypeError: argument of type 'NoneType' is not iterable

I thought this used to work but has anyone else seen this?

Date formatting

You blindly append 'Z' to the end of datetimes which causes problems if the datetime has timezone information. (Such as trying to feed start_time from the output of one request into another)

I'm not sure if only Z is accepted by the api but it would probably be better to use timezone aware datetimes. To convert datetime aware datetimes to be utc without tzinfo I'm using start_time.astimezone(datetime.timezone.utc).replace(tzinfo=None)

Issue with setup.py

So Ill admit, I'm not so great with Python apps, I did not see the appropriate usage of the setup.py file so I cat'd it. Look like it's trying to open README.md, however after cloning the repo the file is all lowercase.
So I renamed it, set the setup file to executable and tried. I get the following errors:

skeer@spektr  /home/git/PyEmVue   master ●  ./setup.py
./setup.py: 1: import: not found
./setup.py: 3: try:: not found
./setup.py: 4: Syntax error: "(" unexpected
✘ skeer@spektr  /home/git/PyEmVue   master ● 

Took a look at the requirements.txt file and there were two truncated characters at the beginning of line 1. I removed those and replaced them with the '^@' like all the other lines, same errors.

Is there a document I missed with regards to dealing with that file in order to use your application?

Thanks!

Need to run twice to get output

I am running this script:
`from pyemvue.enums import Scale, Unit
vue = pyemvue.PyEmVue()
vue.login(username='', password='', token_storage_file='keys.json')

devices = vue.get_devices()
deviceGids = []
for device in devices:
deviceGids.append(device.device_gid)

channel_usage_list = vue.get_devices_usage(deviceGids, None, scale=Scale.SECOND.value,unit=Unit.KWH.value)
for channel in channel_usage_list:
print("%.3f" % (channel.usage*3600), 'kwh')`

Most of the time, the first time I run it (after not running it for say an hour) I get no output. The second, and subsequent executions result in the expected output. Is this a problem with the server?

Installed from HACS, but doesn't list when search.

Core: core-2021.5.5
Supervisor: supervisor-2021.04.3
Installed from HACS by following your instruction and restarted.
But it doesn't list out when search at integration page.
New folder was added at customer_components after installation.

Possible they changed URL's again ?

devices = vue.get_devices()
Traceback (most recent call last):
File "", line 1, in
File "c:\Python38-64\lib\site-packages\pyemvue-0.12.4-py3.8.egg\pyemvue\pyemvue.py", line 40, in get_devices
File "c:\Python38-64\lib\site-packages\requests\models.py", line 941, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.emporiaenergy.com/customers/9695/devices?detailed=true&hie
rarchy=true

print device names with usage

I am trying to play around with pyemvue and the first thing I tried to do was print the device names and their usage. However, I seem to get the names of 5 devices of the 10 that the Emporia app shows. Also, this script takes >30 seconds to run which seems rather excessive.

My script looks like this:

import pyemvue
import time
import json

from pyemvue.enums import Scale, Unit


with open('keys.json') as f:
   data = json.load(f)

vue = pyemvue.PyEmVue()

vue.login(id_token=data['idToken'],
    access_token=data['accessToken'],
    refresh_token=data['refreshToken'],
    token_storage_file='keys.json')

devices = vue.get_devices()
deviceGids = []
for device in devices:
    deviceGids.append(device.device_gid)
    
    devicename = vue.populate_device_properties(device)
    print(devicename.device_name)

channel_usage_list = vue.get_devices_usage(deviceGids, None, scale=Scale.HOUR.value, unit=Unit.KWH.value)

sum=0
for channel in channel_usage_list:
    sum += channel.usage
    print("%2.3f" % channel.usage, `'kwh')

From Emporia: Users of PyEmVue need to avoid too many fetches or repeatedly fetching the same data

Dear Customers:

We appreciate the enthusiasm for Emporia devices but a minority of customers are causing a majority of the load on our servers. Some users of the PyEmVue library are requesting years of Monthly usage data every 2 seconds. That is unnecessary since previous month data won’t change and current month data only changes every hour.

We aren’t cutting off PyEmVue completely, but we plan to introduce limits in the cloud to prevent a few users from overloading the cloud. In the meantime, please be respectful by fetching data less frequently and avoiding re-fetching unchanging data.

best,
Ted

Can this pull from MQTTS?

A few details I found from serial console that smarter people might know what to do with it. Feel free to delete if not relevant.

Snippets..

MQTTComms: MQTT Server Configured: mqtts://a2poo8btpqc3gs-ats.iot.us-east-2.amazonaws.com:8883

MQTTComms: MQTTComms_PublishBinaryReadings Topic: $aws/rules/prodIngestBinaryToSQS/prod/binary/$SERIAL/meter

MQTTComms: TOPIC=prod/minions/emporia/ct/v1/$SERIAL/cmd
MQTTComms: DATA={"cmd":"set","live_meter_updates":60}
MQTTComms: DATA={"cmd":"query_debug"}

MQTTComms: SUBSCRIBE to topic prod/minions/emporia/ct/v1/broadcast/cmd
MQTTComms: SUBSCRIBE to topic prod/minions/emporia/ct/v1/broadcast/fw
MQTTComms: SUBSCRIBE to topic prod/minions/emporia/ct/v1/broadcast/verify

http://fwsrv.emporiaenergy.com:21100

plus two plain text certs and one RSA private key pulled from esptool bin backup.

Erroneous instantaneous readings

Wasn't 100% sure if I should put this here or in magico13/ha-emporia-vue but I think it's actually an issue with the API itself because I see the same problem in the app.

This device pretty much only uses 1300 watts or nothing (it's a space heater) so the amounts given here are definitely wrong. Interestingly in the app looking at the instantaneous reading it give the same wrong value but looking at the history or swapping to 1 minute readings and it looks correct. The way it slowly increases over time is interesting and perhaps hints at what the issue is.

I don't think there's much I can do about it on this side of the API but I wanted to at least write down some info about it and try to keep an eye out for it later. Might be specific to my smart plug hardware, might be an issue with their API. Other devices seem to be giving the correct values.

image

How can I get an outlet's name?

I'm experimenting with your Emporia API. I currently only have an Emporia Smart Plug (aka an outlet device) and can see that device using your API, but I don't see any way to see the name associated with that outlet. Is it possible to do so, and if so, how?

Frequent "None" usage

I have three different types of Emporia devices in my house, all on the same account:

  • Two Gen 2 Vues (monitoring 28 circuits total)
  • One Vue: Utility Connect
  • Eight Smart Plugs

I poll the devices once per minute and log the data.

The usage data for the Gen 2 Vue circuits is reported accurately.

However, for both the Utility Connect and the Smart Plugs, the usage data gets reported as None frequently - here is an example:

Screen Shot 2022-09-07 at 3 34 32 PM

And here is the channel object compared for a valid and invalid result:

instance(VueDeviceChannelUsage):
  channel_multiplier: 1.0,
  channel_num: '1,2,3',
  channel_type_gid: 0,
  device_gid: 72622,
  name: 'Main',
  nested_devices: {
  },
  percentage: 5.7463256452084455,
  timestamp: datetime.datetime(2022, 9, 7, 22, 31, 5, tzinfo=tzutc()),
  usage: 0.0027398242786885723

instance(VueDeviceChannelUsage):
  channel_multiplier: 1.0,
  channel_num: '1,2,3',
  channel_type_gid: 0,
  device_gid: 72622,
  name: 'Main',
  nested_devices: {
  },
  percentage: None,
  timestamp: datetime.datetime(2022, 9, 7, 22, 32, 5, tzinfo=tzutc()),
  usage: None

Based on my historical graphs, it looks like this started happening on August 11th, around 9am Pacific Daylight Time.

I upgraded from 0.16.0 to 0.16.1 and it didn't fix it.

Not able to get_devices()

devices = vue.get_devices() now returns the following error for me:

raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.emporiaenergy.com/customers/XXXXX/devices?detailed=true&hierarchy=true

Has the get_devices() API changed?
The login process returns a True, so it does not seem to be login related.

PS: magico13, thanks for PyEmVue, I would not have purchased my device without this.

How to get In/out to grid kWh

First, thank you for creating this API. I have had great success with it. Among other things, I am using get_chart_usage() to fetch daily energy usage for various circuits.

For the main panel, I can retrieve the net energy flow for the day. We have solar, so power flows in both directions and this number can be positive or negative. However, I'd like to separately query "In from Grid" and "Out to Grid" kWh (what I'm getting is essentially a difference of the two). This should be possible since the Emporia UI shows those numbers separately for durations >= DAY, but I can't figure out how to do that with this API.

Invesitgate issues with API calls failing

Noticed in magico13/ha-emporia-vue#27 and jertel/vuegraf#14.

Feels like a change in the API meaning I'll have some work to do to sniff out the changes and update. Hopefully just a simple fix and not a totally new auth scheme or something that would prevent our access. The app updated recently and is still working so presumably that update included the changes to whatever is different with the API.

SyntaxError: invalid syntax (0.10.1) & ImportError: No module named enums (0.9.9)

installed using setup.py...

PyEmVue-0.10.1# python -m pyemvue ../keys.json
Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 163, in _run_module_as_main
    mod_name, _Error)
  File "/usr/lib/python2.7/runpy.py", line 111, in _get_module_details
    __import__(mod_name)  # Do not catch exceptions initializing package
  File "pyemvue/__init__.py", line 2, in <module>
    from pyemvue.pyemvue import PyEmVue
  File "pyemvue/pyemvue.py", line 85
    raise ValueError(f'Scale of {scale} is invalid, must be 1S, 1MIN, 15MIN, or 1H.')
                                                                                   ^
SyntaxError: invalid syntax

# ls /usr/local/lib/python2.7/dist-packages|grep vue
pyemvue-0.10.1-py2.7.egg

tried downgrading,.. diff error:

PyEmVue-0.9.9# python -m pyemvue ../keys.json
 Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 163, in _run_module_as_main
    mod_name, _Error)
  File "/usr/lib/python2.7/runpy.py", line 111, in _get_module_details
    __import__(mod_name)  # Do not catch exceptions initializing package
  File "pyemvue/__init__.py", line 2, in <module>
    from pyemvue.pyemvue import PyEmVue
  File "pyemvue/pyemvue.py", line 12, in <module>
    from pyemvue.enums import Scale, Unit, TotalTimeFrame, TotalUnit
ImportError: No module named enums
# ls /usr/local/lib/python2.7/dist-packages|grep vue
pyemvue-0.9.9-py2.7.egg


# python --version
Python 2.7.12

also tried w/ python3 w/ same errors.

# python3 --version
Python 3.5.2
# ls /usr/local/lib/python3.5/dist-packages/|grep vue
pyemvue-0.10.1-py3.5.egg

any ideas?

Requesting 1S does not work on chart_usage

Am I not allowed to get chart_usage on a 1S scale?

Failure message:
Exception has occurred: HTTPError
400 Client Error: Bad Request for url: https://api.emporiaenergy.com/AppAPI?apiMethod=getChartUsage&deviceGid=10366&channel=5&start=2021-05-25T04:23:15.941815Z&end=2021-06-01T04:23:15.941859Z&scale=1S&energyUnit=KilowattHours

Fails:
usage_over_time, start_time = vue.get_chart_usage(devices[3].channels[4], datetime.datetime.utcnow()-datetime.timedelta(days=7), datetime.datetime.utcnow(), scale=Scale.SECOND.value, unit=Unit.KWH.value)
usage_over_time, start_time = vue.get_chart_usage(devices[3].channels[4], datetime.datetime.utcnow()-datetime.timedelta(days=7), datetime.datetime.utcnow(), scale=Scale.MINUTE.value, unit=Unit.KWH.value)

Succeeds:
usage_over_time, start_time = vue.get_chart_usage(devices[3].channels[4], datetime.datetime.utcnow()-datetime.timedelta(days=7), datetime.datetime.utcnow(), scale=Scale.MINUTES_15.value, unit=Unit.KWH.value)

usage_over_time, start_time = vue.get_chart_usage(devices[3].channels[4], datetime.datetime.utcnow()-datetime.timedelta(days=7), datetime.datetime.utcnow(), scale=Scale.HOUR.value, unit=Unit.KWH.value)

usage_over_time, start_time = vue.get_chart_usage(devices[3].channels[4], datetime.datetime.utcnow()-datetime.timedelta(days=7), datetime.datetime.utcnow(), scale=Scale.DAY.value, unit=Unit.KWH.value)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.