Skip to content

Commit

Permalink
add more helper scripts (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
vchrisb authored Oct 16, 2023
1 parent af96ae2 commit c47cfc3
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 45 deletions.
5 changes: 5 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ install_requires =
websocket-client
packages = e3dc

[options.extras_require]
develop =
jsbeautifier
argparse

[isort]
profile = black

Expand Down
75 changes: 75 additions & 0 deletions tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Helper Scripts

## install requirements

`pip install pye3dc[develop]`

## Convert RSCP Tags

The script `convert_rscp_tags.py` can be used to generate the `RscpTag(Enum)` class if a new version of the Javascript rscp library (`https://s10.e3dc.com/s10/js/rscpLibV0.9.3.min.js`) is available.

### usage

```
usage: convert_rscp_tags.py [-h] [-r RSCPLIB]
E3DC rscp tags convert
options:
-h, --help show this help message and exit
-r RSCPLIB, --rscpLib RSCPLIB
rscp library file
```

## Run tests

The script `test.py` will run all non altering methods for `pye3dc` for testing or sharing the output.

This comment has been minimized.

Copy link
@eikowagenknecht

eikowagenknecht Oct 16, 2023

Contributor

should be tests.py


### usage

```
usage: tests.py [-h] [-c CONFIG] -i IPADDRESS -u USERNAME -p PASSWORD -k KEY
E3DC tests
options:
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
config of E3DC
required named arguments:
-i IPADDRESS, --ipaddress IPADDRESS
IP address of E3DC
-u USERNAME, --username USERNAME
username of E3DC
-p PASSWORD, --password PASSWORD
password of E3DC
-k KEY, --key KEY key of E3DC
```

## Run tests for different python versions

The script `testcontainers.py` wil run the `tests`, using docker, for multiple Python versions supported by this library.

### usage

```
usage: testcontainers.py [-h] [-l LIST] [-c CONFIG] -i IPADDRESS -u USERNAME -p PASSWORD -k KEY
E3DC testcontainers
options:
-h, --help show this help message and exit
-l LIST, --list LIST list of Python versions to test with
-c CONFIG, --config CONFIG
config of E3DC
required named arguments:
-i IPADDRESS, --ipaddress IPADDRESS
IP address of E3DC
-u USERNAME, --username USERNAME
username of E3DC
-p PASSWORD, --password PASSWORD
password of E3DC
-k KEY, --key KEY key of E3DC
```
45 changes: 0 additions & 45 deletions tools/_convert_rscp_tags.py

This file was deleted.

52 changes: 52 additions & 0 deletions tools/convert_rscp_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""This is a helper script to convert the enumerations from the "official" RSCP implementation into a format that can be used in the Python implementation.
Requirements (just for this script):
pip install pye3dc[develop]
"""

import argparse
import re
import sys

import jsbeautifier
import requests

parser = argparse.ArgumentParser(description="E3DC rscp tags convert")
parser.add_argument(
"-r", "--rscpLib", help="rscp library file", default="rscpLibV0.9.3.min.js"
)
args = vars(parser.parse_args())

rscpLib = args["rscpLib"]
source = requests.get(
"https://s10.e3dc.com/s10/js/{}".format(rscpLib), allow_redirects=True
)
if source.status_code != 200:
print("Can't download {}".format(rscpLib), file=sys.stderr)
exit(1)
input = jsbeautifier.beautify(str(source.content, encoding="utf-8"))

rscpTagsFromJS = re.search(
r"var rscpTags = {(.*?)getHexTag.*?}", input, re.DOTALL
).group(1)

lines = rscpTagsFromJS.splitlines()

print("class RscpTag(Enum):")
print(
' """All available RSCP tags. Generated from https://s10.e3dc.com/s10/js/{}."""\n'.format(
rscpLib
)
)

for line in lines:
line = line.strip()
if not line:
continue
number, string = line.split(": ")
number = number.strip()
hex_number = hex(int(float(number))).upper()[2:]
padded_hex_number = hex_number.zfill(8)
name = string.removeprefix('"').removesuffix('",').strip()
enum_entry = f" {name} = 0x{padded_hex_number}"
print(enum_entry)
102 changes: 102 additions & 0 deletions tools/testcontainers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"""A simple python script to test the e3dc module with various python versions in docker."""

import argparse
import json
from pathlib import Path

import docker


class Testcontainers:
"""A class to run commands in a python container."""

container = ""
version = ""

def __init__(
self,
ipAddress,
username,
password,
key,
configuration,
version="3.8",
):
"""The init method for Testcontainers."""
client = docker.from_env()
self.version = version
image_name = "python:" + version
container_name = "python-e3dc-" + version
client.images.pull(image_name)
try:
client.containers.get(container_name).remove(force=True)
except docker.errors.NotFound:
pass
self.container = client.containers.run(
image_name,
name=container_name,
stdin_open=True,
remove=True,
detach=True,
volumes=[str(Path(__file__).resolve().parents[1]) + ":/pye3dc"],
working_dir="/pye3dc",
environment={
"IPADDRESS": ipAddress,
"USERNAME": username,
"PASSWORD": password,
"KEY": key,
"CONFIG": configuration,
},
)

def exec_cmd_stream(self, command):
"""Execute a command and stream output."""
_, stream = self.container.exec_run(cmd=command, stream=True)
for data in stream:
print(data.decode(), end="")

def exec_cmd(self, command):
"""Execute a command and validate return code."""
result, output = self.container.exec_run(cmd=command)
print(output.decode())
if result != 0:
exit(1)

def remove(self):
"""Remove the test container."""
self.container.remove(force=True)


parser = argparse.ArgumentParser(description="E3DC testcontainers")
parser.add_argument(
"-l",
"--list",
help="list of Python versions to test with",
default='["3.8", "3.9", "3.10", "3.11", "3.12"]',
)
parser.add_argument("-c", "--config", help="config of E3DC", default="{}")
requiredNamed = parser.add_argument_group("required named arguments")
requiredNamed.add_argument(
"-i", "--ipaddress", help="IP address of E3DC", required=True
)
requiredNamed.add_argument("-u", "--username", help="username of E3DC", required=True)
requiredNamed.add_argument("-p", "--password", help="password of E3DC", required=True)
requiredNamed.add_argument("-k", "--key", help="key of E3DC", required=True)
args = vars(parser.parse_args())

for version in json.loads(args["list"]):
print("Starting test on Python " + version + ":")
testcontainers = Testcontainers(
ipAddress=args["ipaddress"],
username=args["username"],
password=args["password"],
key=args["key"],
configuration=args["config"],
version=version,
)
testcontainers.exec_cmd("pip install .")
testcontainers.exec_cmd(
"sh -c 'python tools/tests.py -i $IPADDRESS -u $USERNAME -p $PASSWORD -k $KEY -c $CONFIG'"
)
testcontainers.remove()
print()
63 changes: 63 additions & 0 deletions tools/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""A simple python script to test the e3dc module."""

import argparse
import json
from datetime import date, datetime

from e3dc import E3DC


def json_serial(obj):
"""JSON serializer for objects not serializable by default json code."""
if isinstance(obj, (datetime, date)):
return obj.isoformat()
raise TypeError("Type %s not serializable" % type(obj))


def printJson(obj):
"""Print a json object with a datetime obect."""
print(json.dumps(obj, indent=2, default=json_serial))


parser = argparse.ArgumentParser(description="E3DC tests")
parser.add_argument("-c", "--config", help="config of E3DC", default="{}")
requiredNamed = parser.add_argument_group("required named arguments")
requiredNamed.add_argument(
"-i", "--ipaddress", help="IP address of E3DC", required=True
)
requiredNamed.add_argument("-u", "--username", help="username of E3DC", required=True)
requiredNamed.add_argument("-p", "--password", help="password of E3DC", required=True)
requiredNamed.add_argument("-k", "--key", help="key of E3DC", required=True)
args = vars(parser.parse_args())

e3dc = E3DC(
E3DC.CONNECT_LOCAL,
ipAddress=args["ipaddress"],
username=args["username"],
password=args["password"],
key=args["key"],
configuration=json.loads(args["config"]),
)

methods = [
"poll",
"poll_switches",
"get_idle_periods",
"get_db_data",
"get_system_info",
"get_system_status",
"get_battery_data",
"get_batteries_data",
"get_pvi_data",
"get_pvis_data",
"get_powermeters",
"get_powermeter_data",
"get_powermeters_data",
"get_power_settings",
]

for method in methods:
print(method + "():")
method = getattr(e3dc, method)
printJson(method(keepAlive=True))
print()

0 comments on commit c47cfc3

Please sign in to comment.