magico13 / PyEmVue

Python Library for the Emporia Vue Energy Monitor
MIT License
185 stars 36 forks source link

Documentation examples need to be improved #32

Open natbesh opened 2 years ago

natbesh commented 2 years ago

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

natbesh commented 2 years ago

something like-a this:

!/usr/bin/python3

import json import pyemvue from datetime import datetime

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'{name} {channel.usage60} kwh') if channel.nested_devices: print_recursive(channel.nested_devices, depth+1)

vue = pyemvue.PyEmVue() vue.login(username='email@email', password='password', token_storage_file='keys.json')

devices = vue.get_devices()

device_gids = []

info = {}

for device in devices: if not device.device_gid in device_gids: device_gids.append(device.device_gid) info[device.device_gid] = device else: info[device.device_gid].channels += device.channels

device_usage_dict = vue.get_device_list_usage(deviceGids=device_gids, instant=datetime.now(), scale='1MIN', unit='KilowattHours') print_recursive(device_usage_dict, info)

wgrover commented 2 years ago

This is a full working example based on @natbesh's example above, edited slightly and formatted as a code block so the indentation is more evident:

from pyemvue import PyEmVue

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, depth+1)

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

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

device_usage_dict = vue.get_device_list_usage(deviceGids=device_gids, instant=None, scale="1MIN", unit="KilowattHours")
print_recursive(device_usage_dict, info)
sbates130272 commented 1 year ago

@wgrover your example is missing the import statements at the top. I think to make your block work as a stand-alone prograem you need to add

#!/usr/bin/python3

import json
import pyemvue
from datetime import datetime
magico13 commented 1 year ago

The readme should now have a better example script showing a "Typical Example". Below is the script as present in the readme.

#!/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)
dalklein commented 4 months ago

Here's a working example for EVSE control. I use a shell script that runs pyemvue in a venv, passing the desired charge current. The py script will turn on the charger if the requested current is 6 or above, and will limit the request to the max current that the charger is already set to based on your circuit breaker continuous rating. If the requested current is below 6, then it turns the charger off.

EVSE_cmd.sh This is called from node-red with the desired charging current as a command line argument

#!/bin/bash

source /home/pi/PyEmVue/.venv/bin/activate
cd /home/pi/PyEmVue
python3 /home/pi/PyEmVue/evse_cmd.py "$1"
deactivate

evse_cmd.py

import sys
import string
import json
from pyemvue.pyemvue import PyEmVue

#print(' Enter integer Amps to charge, >5 enables charging, <=5 pauses charging')
#chgrcmd = sys.stdin.readline() # read the stdin from the inject node, wait for it to be typed

#get command from input argument:
chgrcmd = sys.argv[1]    # input 0 is the file being run, input 1 is first arg, charge amps cmd
chgr_cmd = int(chgrcmd)
#print(f'chgr_cmd {chgr_cmd} \n')

vue = PyEmVue()
vue.login(token_storage_file='keys.json')
#print('Logged in.')
#print()

chargers = vue.get_chargers()       # get current status
for charger in chargers:

    if ( (chgr_cmd < 6 and charger.charger_on) \
                                                    # if command off, while charger was on
        or (chgr_cmd > 5 and not(charger.charger_on)) \
                                                    # or command on, while charger was off
        or chgr_cmd != charger.charging_rate ):    # or change in charge amps,    then an update is required

   #     print(f'EVSE dev_gid {charger.device_gid} status \n\
   #         On? {charger.charger_on} Charge rate: {charger.charging_rate}A/{charger.max_charging_rate}A')
#    vue.update_charger(charger, on=(not charger.charger_on), charge_rate=charger.max_charging_rate)
    # alternatively you can update the charger object first

        if chgr_cmd > 5:
            charger.charger_on = True
            charger.charging_rate = min(chgr_cmd,24)      # prevent setting higher than our current 30A breaker
#            charger.charging_rate = min(chgr_cmd,charger.max_charging_rate)
        else:
            charger.charger_on = False
            charger.charging_rate = 6

        charger = vue.update_charger(charger)         # update the charger

    else:
#        print(f'EVSE dev_gid {charger.device_gid} status, no update reqd \n\
#            On? {charger.charger_on} Charge rate: {charger.charging_rate}A/{charger.max_charging_rate}A')
        time.sleep(1)

# report status
EVSE_dict = {'dev_gid': charger.device_gid,
    'message':      charger.message,
    'status':       charger.status,
    'icon':         charger.icon,
    'icon_lbl':     charger.icon_label,
    'icon_det_txt': charger.icon_detail_text,
    'fault':        charger.fault_text,
    'On?':          charger.charger_on,
    'Chg_rate':     charger.charging_rate,
    'Max_Chg_rate': charger.max_charging_rate}
EVSE_json = json.dumps(EVSE_dict)

print(EVSE_json)
Merca60 commented 1 month ago

Dear magico13, using your example(s) I obtained correct results only with the one you shown results in the "readme.md" file. I'm aware to need learnig on Python, Java and more other things, like a lot of people...

For a programmer like you it's easy and fast to complete coding of your examples, but a lot of us dont'know too much things. During my training I made various trite errors, (syntax and others), after I founded Spyder, it's a great help to have a correct Python syntax.

Then, in the first example of readme.md file we obtain the list of instant data of all devices matched with our Emporia's account. It's correct, I have two devices and I obtain both's data. (Not always, and sometimes not all, I think it depend from the instant conection quality)

During last year I red a lot of news, forum etc on Emporia vue, like the Emporia's staff criticism on the enormous quantity of requests to them servers originated by your software, and it's normal, because if you need to obtain high resolution data you'll ask continuosly to servers...

So I'd like to ask only when I need, for example for a second resolution every less than three hours, because three hours are the limit of seconds interval on Emporia servers. (O three days for the minute, and so on).

It is the readme.md section I thought to use.

### Get usage over time

# ```python
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.

It is the code I wrote the first time, adding the first two rows from the other code.

import pyemvue 
from pyemvue.enums import Scale, Unit

### Get usage over time

# ```python
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.

Obtaining the next message on the console.

Traceback (most recent call last):
  File "/home/ammi/PyEmVue-master/PyEmVue/PPyEmVue_27.py", line 15, in <module>
    vue = pyemvue()
TypeError: 'module' object is not callable

It is the code I wrote the second time (replacing the "vue =" rows with the other proven for my account access).

import pyemvue 
from pyemvue.enums import Scale, Unit

# Crea l'oggetto "vue" (?)
vue = pyemvue.PyEmVue()
vue.login(username='MIAMAIL', password='MIAPASSWORD', token_storage_file='keys=json')
# 

### Get usage over time

## # ```python
## 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.

Obtaining the next message on the console.

Traceback (most recent call last):
  File "/home/ammi/PyEmVue-master/PyEmVue/PPyEmVue_28.py", line 26, in <module>
    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)
NameError: name 'datetime' is not defined

It is the code I wrote the third time (inserting datatime call).

import pyemvue 
from pyemvue.enums import Scale, Unit
from datetime import datetime

# Crea l'oggetto "vue" (?)
vue = pyemvue.PyEmVue()
vue.login(username='MIAMAIL', password='MIAPASSWORD', token_storage_file='keys=json')
# 

### Get usage over time

## # ```python
## 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.

Obtaining the next message on the console.

Traceback (most recent call last):
  File "/home/ammi/PyEmVue-master/PyEmVue/PPyEmVue_28.py", line 26, in <module>
    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)
AttributeError: type object 'datetime.datetime' has no attribute 'datetime'

So I need to ask to you.

I think you could write some code rows more than actual readme file... I hope it.