Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb39567d05 | ||
|
|
b6431f8448 | ||
|
|
714dd92f35 | ||
|
|
02861f70af | ||
|
|
942e17d7c3 | ||
|
|
37f7052811 | ||
|
|
05e446dc74 | ||
|
|
647ef157d4 | ||
|
|
9ae391b46d |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.5.2] - 2023-11-09
|
||||
|
||||
- add int64 data type to info parser
|
||||
- allow multiple calls to Message.close()
|
||||
- check for race cond. on closing and establishing client connections
|
||||
|
||||
## [0.5.1] - 2023-11-05
|
||||
|
||||
- fixes f-string by limes007
|
||||
- add description for dns settings by limes007
|
||||
|
||||
## [0.5.0] - 2023-11-04
|
||||
|
||||
- fix issue [#21](https://github.com/s-allius/tsun-gen3-proxy/issues/21)
|
||||
|
||||
17
README.md
17
README.md
@@ -131,6 +131,23 @@ suggested_area = 'balcony' # Optional, suggested installation area for home-a
|
||||
|
||||
```
|
||||
|
||||
## DNS Settings
|
||||
|
||||
### Loop the proxy into the connection
|
||||
To include the proxy in the connection between the inverter and the TSUN Cloud, you must adapt the DNS record of *logger.talent-monitoring.com* within the network that your inverter uses. You need a mapping from logger.talent-monitoring.com to the IP address of the host running the Docker engine.
|
||||
|
||||
This can be done, for example, by adding a local DNS record to the Pi-hole if you are using it.
|
||||
|
||||
### DNS Rebind Protection
|
||||
If you are using a router as local DNS server, the router may have DNS rebind protection that needs to be adjusted. For security reasons, DNS rebind protection blocks DNS queries that refer to an IP address on the local network.
|
||||
|
||||
If you are using a FRITZ!Box, you can do this in the Network Settings tab under Home Network / Network. Add logger.talent-monitoring.com as a hostname exception in DNS rebind protection.
|
||||
|
||||
### DNS server of proxy
|
||||
The proxy itself must use a different DNS server to connect to the TSUN Cloud. If you use the DNS server with the adapted record, you will end up in an endless loop as soon as the proxy tries to send data to the TSUN Cloud.
|
||||
|
||||
As described above, set a DNS sever in the Docker command or Docker compose file.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [BSD 3-clause License](https://opensource.org/licenses/BSD-3-Clause).
|
||||
|
||||
@@ -16,11 +16,15 @@ class AsyncStream(Message):
|
||||
self.writer = writer
|
||||
self.remoteStream = remote_stream
|
||||
self.addr = addr
|
||||
self.r_addr = ''
|
||||
self.l_addr = ''
|
||||
|
||||
'''
|
||||
Our puplic methods
|
||||
'''
|
||||
async def loop(self) -> None:
|
||||
async def loop(self):
|
||||
self.r_addr = self.writer.get_extra_info('peername')
|
||||
self.l_addr = self.writer.get_extra_info('sockname')
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -35,26 +39,27 @@ class AsyncStream(Message):
|
||||
ConnectionAbortedError,
|
||||
BrokenPipeError,
|
||||
RuntimeError) as error:
|
||||
logger.warning(f'In loop for {self.addr}: {error}')
|
||||
logger.warning(f'In loop for l{self.l_addr} | '
|
||||
f'r{self.r_addr}: {error}')
|
||||
self.close()
|
||||
return
|
||||
return self
|
||||
except Exception:
|
||||
logger.error(
|
||||
f"Exception for {self.addr}:\n"
|
||||
f"{traceback.format_exc()}")
|
||||
self.close()
|
||||
return
|
||||
return self
|
||||
|
||||
def disc(self) -> None:
|
||||
logger.debug(f'in AsyncStream.disc() {self.addr}')
|
||||
logger.debug(f'in AsyncStream.disc() l{self.l_addr} | r{self.r_addr}')
|
||||
self.writer.close()
|
||||
|
||||
def close(self):
|
||||
logger.debug(f'in AsyncStream.close() {self.addr}')
|
||||
logger.debug(f'in AsyncStream.close() l{self.l_addr} | r{self.r_addr}')
|
||||
self.writer.close()
|
||||
super().close() # call close handler in the parent class
|
||||
|
||||
# logger.info (f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
# logger.info(f'AsyncStream refs: {gc.get_referrers(self)}')
|
||||
|
||||
'''
|
||||
Our private methods
|
||||
@@ -96,4 +101,4 @@ class AsyncStream(Message):
|
||||
pass
|
||||
|
||||
def __del__(self):
|
||||
logging.debug(f"AsyncStream.__del__ {self.addr}")
|
||||
logging.debug(f"AsyncStream.__del__ l{self.l_addr} | r{self.r_addr}")
|
||||
|
||||
@@ -341,6 +341,9 @@ class Infos:
|
||||
elif data_type == 0x46: # 'F' -> float32
|
||||
result = round(struct.unpack_from('!f', buf, ind)[0], 2)
|
||||
ind += 4
|
||||
elif data_type == 0x4c: # 'L' -> int64
|
||||
result = struct.unpack_from('!q', buf, ind)[0]
|
||||
ind += 8
|
||||
else:
|
||||
self.inc_counter('Invalid_Data_Type')
|
||||
logging.error(f"Infos.parse: data_type: {data_type}"
|
||||
@@ -374,6 +377,6 @@ class Infos:
|
||||
name = str(f'info-id.0x{info_id:x}')
|
||||
|
||||
self.tracer.log(level, f'{name} : {result}{unit}'
|
||||
' update: {update}')
|
||||
f' update: {update}')
|
||||
|
||||
i += 1
|
||||
|
||||
@@ -107,7 +107,7 @@ class Inverter(AsyncStream):
|
||||
self.inc_counter('Inverter_Cnt')
|
||||
await self.loop()
|
||||
self.dec_counter('Inverter_Cnt')
|
||||
logging.info(f'Server loop stopped for {addr}')
|
||||
logging.info(f'Server loop stopped for r{self.r_addr}')
|
||||
|
||||
# if the server connection closes, we also have to disconnect
|
||||
# the connection to te TSUN cloud
|
||||
@@ -121,15 +121,22 @@ class Inverter(AsyncStream):
|
||||
|
||||
async def client_loop(self, addr):
|
||||
'''Loop for receiving messages from the TSUN cloud (client-side)'''
|
||||
await self.remoteStream.loop()
|
||||
logging.info(f'Client loop stopped for {addr}')
|
||||
clientStream = await self.remoteStream.loop()
|
||||
logging.info(f'Client loop stopped for l{clientStream.l_addr}')
|
||||
|
||||
# if the client connection closes, we don't touch the server
|
||||
# connection. Instead we erase the client connection stream,
|
||||
# thus on the next received packet from the inverter, we can
|
||||
# establish a new connection to the TSUN cloud
|
||||
self.remoteStream.remoteStream = None # erase backlink to inverter
|
||||
self.remoteStream = None # than erase client connection
|
||||
|
||||
# erase backlink to inverter
|
||||
clientStream.remoteStream = None
|
||||
|
||||
if self.remoteStream == clientStream:
|
||||
# logging.debug(f'Client l{clientStream.l_addr} refs:'
|
||||
# f' {gc.get_referrers(clientStream)}')
|
||||
# than erase client connection
|
||||
self.remoteStream = None
|
||||
|
||||
async def async_create_remote(self) -> None:
|
||||
'''Establish a client connection to the TSUN cloud'''
|
||||
@@ -197,7 +204,7 @@ class Inverter(AsyncStream):
|
||||
f"/{node_id}{id}/config", data_json)
|
||||
|
||||
def close(self) -> None:
|
||||
logging.debug(f'Inverter.close() {self.addr}')
|
||||
logging.debug(f'Inverter.close() l{self.l_addr} | r{self.r_addr}')
|
||||
super().close() # call close handler in the parent class
|
||||
# logger.debug (f'Inverter refs: {gc.get_referrers(self)}')
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ class Message(metaclass=IterRegistry):
|
||||
# we have refernces to methods of this class in self.switch
|
||||
# so we have to erase self.switch, otherwise this instance can't be
|
||||
# deallocated by the garbage collector ==> we get a memory leak
|
||||
del self.switch
|
||||
self.switch.clear()
|
||||
|
||||
def inc_counter(self, counter: str) -> None:
|
||||
self.db.inc_counter(counter)
|
||||
|
||||
Reference in New Issue
Block a user