Merge pull request #5 from evanrich/python3
Migrate to Python3 and add pricing info
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
FROM python:2.7.15-alpine3.8
|
FROM python:3.7.0-alpine3.8
|
||||||
|
|
||||||
LABEL maintainer="Evan Richardson"
|
LABEL maintainer="Evan Richardson"
|
||||||
LABEL version="1.0"
|
LABEL version="1.1"
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . /app
|
COPY . /app
|
||||||
ENV PYTHONPATH=/app/src/python
|
ENV PYTHONPATH=/app/src/python
|
||||||
RUN pip install --upgrade pip
|
RUN pip3 install --upgrade pip
|
||||||
RUN pip install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
RUN rm -rf /var/cache/apk
|
#RUN rm -rf /var/cache/apk
|
||||||
|
|
||||||
CMD ["/app/src/bin/tHome-eagle.py", "-c", "/app/src/conf"]
|
CMD ["/app/src/bin/tHome-eagle.py", "-c", "/app/src/conf"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
#
|
#
|
||||||
@@ -17,9 +17,9 @@ messages.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import bottle as B
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import bottle as B
|
||||||
import tHome as T
|
import tHome as T
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
@@ -41,6 +41,15 @@ def instant( client, data, cfg ):
|
|||||||
|
|
||||||
return ( cfg.mqttPower, msg )
|
return ( cfg.mqttPower, msg )
|
||||||
|
|
||||||
|
#===========================================================================
|
||||||
|
def price( client, data, cfg ):
|
||||||
|
msg = {
|
||||||
|
"time" : data.TimeUnix,
|
||||||
|
"price" : data.Price,
|
||||||
|
"tier" : data.Tier,
|
||||||
|
}
|
||||||
|
return ( cfg.mqttPrice, msg )
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
handlers = {
|
handlers = {
|
||||||
#"BlockPriceDetail" :
|
#"BlockPriceDetail" :
|
||||||
@@ -51,7 +60,7 @@ handlers = {
|
|||||||
#"MessageCluster" :
|
#"MessageCluster" :
|
||||||
#"MeterInfo" :
|
#"MeterInfo" :
|
||||||
#"NetworkInfo" :
|
#"NetworkInfo" :
|
||||||
#"PriceCluster" :
|
"PriceCluster" : price,
|
||||||
#"Reading" :
|
#"Reading" :
|
||||||
#"ScheduleInfo" :
|
#"ScheduleInfo" :
|
||||||
#"TimeCluster" :
|
#"TimeCluster" :
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import os
|
|||||||
#
|
#
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
host = os.getenv('MQTT_BROKER_IP', '192.168.1.20')
|
host = os.getenv('MQTT_BROKER_IP', '192.168.1.20')
|
||||||
port = os.getenv('MQTT_BROKER_PORT', 1883)
|
port = os.getenv('MQTT_BROKER_PORT', 31333)
|
||||||
|
|
||||||
# Keep alive time in seconds. Client sends a ping if no other message
|
# Keep alive time in seconds. Client sends a ping if no other message
|
||||||
# is sent in this interval.
|
# is sent in this interval.
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ mqttEnergy = 'power/elec/Home/energy'
|
|||||||
# Instantaneous power usage topic (reports power usage in W)
|
# Instantaneous power usage topic (reports power usage in W)
|
||||||
mqttPower = 'power/elec/Home/power'
|
mqttPower = 'power/elec/Home/power'
|
||||||
|
|
||||||
|
#Current price topic (returns current price of electricity from meter)
|
||||||
|
mqttPrice = 'power/elec/Home/price'
|
||||||
|
|
||||||
|
#Current rate label (returns rate label from meter)
|
||||||
|
mqttRateLabel = 'power/elec/Home/ratelabel'
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
#
|
#
|
||||||
# Logging configuration. Env variables are allowed in the file name.
|
# Logging configuration. Env variables are allowed in the file name.
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
import tHome as T
|
import tHome as T
|
||||||
|
|
||||||
d = T.config.parse( "/home/ted/proj/tHome/conf" )
|
d = T.config.parse( "/home/ted/proj/tHome/conf" )
|
||||||
print d
|
print(d)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
import StringIO
|
import io
|
||||||
|
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
class Data:
|
class Data:
|
||||||
@@ -11,7 +11,7 @@ class Data:
|
|||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
def keys( self ):
|
def keys( self ):
|
||||||
return self.__dict__.keys()
|
return list(self.__dict__.keys())
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
def update( self, rhs ):
|
def update( self, rhs ):
|
||||||
@@ -43,7 +43,7 @@ class Data:
|
|||||||
def _formatValue( self, value, out, indent ):
|
def _formatValue( self, value, out, indent ):
|
||||||
if isinstance( value, Data ):
|
if isinstance( value, Data ):
|
||||||
out.write( "%s(\n" % self.__class__.__name__ )
|
out.write( "%s(\n" % self.__class__.__name__ )
|
||||||
for k, v in sorted( value.__dict__.iteritems() ):
|
for k, v in sorted( value.__dict__.items() ):
|
||||||
if k[0] == "_":
|
if k[0] == "_":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class Data:
|
|||||||
|
|
||||||
elif isinstance( value, dict ):
|
elif isinstance( value, dict ):
|
||||||
out.write( "{\n" )
|
out.write( "{\n" )
|
||||||
for k, v in sorted( value.iteritems() ):
|
for k, v in sorted( value.items() ):
|
||||||
if k[0] == "_":
|
if k[0] == "_":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Error ( Exception ):
|
|||||||
|
|
||||||
exception.add( msg )
|
exception.add( msg )
|
||||||
|
|
||||||
raise exception, None, trace
|
raise exception.with_traceback(trace)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -34,7 +34,7 @@ class Error ( Exception ):
|
|||||||
newError = Error( str( exception ) )
|
newError = Error( str( exception ) )
|
||||||
newError.add( msg )
|
newError.add( msg )
|
||||||
|
|
||||||
raise newError, None, trace
|
raise newError.with_traceback(trace)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
def __init__( self, msg ):
|
def __init__( self, msg ):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def fimport( filePath ):
|
|||||||
# Create a new module and exec the code in it's context.
|
# Create a new module and exec the code in it's context.
|
||||||
m = imp.new_module( rootName )
|
m = imp.new_module( rootName )
|
||||||
m.__file__ = absPath
|
m.__file__ = absPath
|
||||||
exec code in m.__dict__
|
exec(code, m.__dict__)
|
||||||
|
|
||||||
# Return the module object.
|
# Return the module object.
|
||||||
return m
|
return m
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Dump hex bytes to a table.
|
# Dump hex bytes to a table.
|
||||||
#
|
#
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
import StringIO
|
import io
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def dump( buf ):
|
def dump( buf ):
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def loads( text ):
|
|||||||
#=============================================================================
|
#=============================================================================
|
||||||
def _toStr( data, ignoreDicts=False ):
|
def _toStr( data, ignoreDicts=False ):
|
||||||
# Convert unicode to string.
|
# Convert unicode to string.
|
||||||
if isinstance( data, unicode ):
|
if isinstance( data, str ):
|
||||||
return data.encode( 'utf-8' )
|
return data.encode( 'utf-8' )
|
||||||
|
|
||||||
# For lists, process each item.
|
# For lists, process each item.
|
||||||
@@ -45,7 +45,7 @@ def _toStr( data, ignoreDicts=False ):
|
|||||||
if isinstance( data, dict ) and not ignoreDicts:
|
if isinstance( data, dict ) and not ignoreDicts:
|
||||||
return {
|
return {
|
||||||
_toStr( k, ignoreDicts=True ) : _toStr( v, ignoreDicts=True )
|
_toStr( k, ignoreDicts=True ) : _toStr( v, ignoreDicts=True )
|
||||||
for k, v in data.iteritems()
|
for k, v in data.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Otherwise return the original object.
|
# Otherwise return the original object.
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class Poll:
|
|||||||
# themselves. So make a copy of the dict value list list
|
# themselves. So make a copy of the dict value list list
|
||||||
# containing all the objects so we're not modifying the client
|
# containing all the objects so we're not modifying the client
|
||||||
# dictionary as we loop over it.
|
# dictionary as we loop over it.
|
||||||
clients = self.clients.values()[:]
|
clients = list(self.clients.values())[:]
|
||||||
for c in clients:
|
for c in clients:
|
||||||
c.close()
|
c.close()
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ class Poll:
|
|||||||
# Returns tuple (fileDescriptor, bitFlag) of the files
|
# Returns tuple (fileDescriptor, bitFlag) of the files
|
||||||
# that can act.
|
# that can act.
|
||||||
events = self.poll.poll( timeOut_msec )
|
events = self.poll.poll( timeOut_msec )
|
||||||
except select.error, v:
|
except select.error as v:
|
||||||
# Not sure why, but sometimes with a timeout value, you can
|
# Not sure why, but sometimes with a timeout value, you can
|
||||||
# get an "interrupted system call" error thrown. Web
|
# get an "interrupted system call" error thrown. Web
|
||||||
# searches indicate this isn't really an error and should be
|
# searches indicate this isn't really an error and should be
|
||||||
|
|||||||
@@ -2,18 +2,18 @@
|
|||||||
from tHome.util import Data
|
from tHome.util import Data
|
||||||
|
|
||||||
d = Data( a=1, b="asdf", c=2 )
|
d = Data( a=1, b="asdf", c=2 )
|
||||||
print d
|
print(d)
|
||||||
print "----"
|
print("----")
|
||||||
|
|
||||||
d = Data( a=1, b="asdf", c=[2,3,4] )
|
d = Data( a=1, b="asdf", c=[2,3,4] )
|
||||||
print d
|
print(d)
|
||||||
print "----"
|
print("----")
|
||||||
|
|
||||||
d = Data( a=1, b="asdf", c={'a':3, 'b':4} )
|
d = Data( a=1, b="asdf", c={'a':3, 'b':4} )
|
||||||
print d
|
print(d)
|
||||||
print "----"
|
print("----")
|
||||||
|
|
||||||
d = Data( a=1, b=[ Data(a=1,b=2) ], c={'a':3, 'b':[1,2,3]} )
|
d = Data( a=1, b=[ Data(a=1,b=2) ], c={'a':3, 'b':[1,2,3]} )
|
||||||
print d
|
print(d)
|
||||||
print "----"
|
print("----")
|
||||||
|
|
||||||
|
|||||||
1
TODO.md
1
TODO.md
@@ -1,6 +1,5 @@
|
|||||||
## TODO
|
## TODO
|
||||||
1. Need to add variables for username/password, in case anyone is using authentication with their broker
|
1. Need to add variables for username/password, in case anyone is using authentication with their broker
|
||||||
1. Need to try and port original code to Python 3.x
|
|
||||||
1. Make sure Dockerhub is set up to build when I want it to
|
1. Make sure Dockerhub is set up to build when I want it to
|
||||||
1. Look for ways to optimize the Dockerfile to reduce image size
|
1. Look for ways to optimize the Dockerfile to reduce image size
|
||||||
1. Try to get more stats from the Eagle ($/kWh from the meter, etc.)
|
1. Try to get more stats from the Eagle ($/kWh from the meter, etc.)
|
||||||
|
|||||||
Reference in New Issue
Block a user