modulitiz-micro 2.45.0__py311-none-any.whl → 2.46.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modulitiz_micro/ModuloSeriale.py +70 -70
- modulitiz_micro/ModuloTarghe.py +47 -47
- modulitiz_micro/database/AbstractDatabaseService.py +13 -13
- modulitiz_micro/database/AbstractSql.py +69 -69
- modulitiz_micro/database/ModuloSqlOracle.py +19 -19
- modulitiz_micro/database/ModuloSqlServer.py +43 -43
- modulitiz_micro/database/eccezioni/EccezioneDbNoData.py +6 -6
- modulitiz_micro/database/mysql/AbstractBasicMysql.py +114 -114
- modulitiz_micro/database/mysql/ModuloMysql.py +163 -163
- modulitiz_micro/database/mysql/MysqlCommonConverter.py +47 -47
- modulitiz_micro/database/mysql/eccezioni/EccezioneMysqlOffline.py +6 -6
- modulitiz_micro/database/sqlite/AbstractBasicSQLite.py +114 -114
- modulitiz_micro/database/sqlite/ModuloSQLite.py +82 -82
- modulitiz_micro/eccezioni/EccezioneCtrlC.py +7 -7
- modulitiz_micro/eccezioni/EccezioneScheduler.py +7 -7
- modulitiz_micro/eccezioni/http/EccezioneHttp.py +8 -8
- modulitiz_micro/eccezioni/http/EccezioneHttp404.py +7 -7
- modulitiz_micro/eccezioni/http/EccezioneHttpGeneric.py +7 -7
- modulitiz_micro/files/cache/DatabaseCache.py +91 -91
- modulitiz_micro/files/cache/decorators/cacheRam.py +26 -26
- modulitiz_micro/files/git/ModuloGit.py +28 -28
- modulitiz_micro/files/git/decorators/catchAndRaiseGitExceptions.py +19 -19
- modulitiz_micro/files/git/exceptions/EccezioneGit.py +7 -7
- modulitiz_micro/gestionedom/GestioneDom.py +44 -44
- modulitiz_micro/iot/ModuleIotDevice.py +62 -62
- modulitiz_micro/keylogger/EccezioneKeyLogger.py +7 -7
- modulitiz_micro/keylogger/ModuloKeylogger.py +73 -73
- modulitiz_micro/rete/ModuleAndroidTVRemote.py +107 -0
- modulitiz_micro/rete/ModuloNetworking.py +67 -72
- modulitiz_micro/rete/ModuloOpenVpn.py +15 -15
- modulitiz_micro/rete/email/EmailBean.py +5 -5
- modulitiz_micro/rete/email/ModuloEmail.py +90 -90
- modulitiz_micro/rete/http/ModuloHttp.py +119 -119
- modulitiz_micro/rete/http/ModuloHttpConnectionSafe.py +91 -91
- modulitiz_micro/rete/http/ModuloHttpUtils.py +69 -69
- modulitiz_micro/rete/http/beans/HttpResponseBean.py +5 -5
- modulitiz_micro/rete/http/decorators/catchAndRaiseHttpExceptions.py +22 -22
- modulitiz_micro/rete/http/huawei/fusionsolar/ModuleHuaweiFusionSolar.py +84 -84
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/TokenBean.py +28 -28
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceBean.py +6 -6
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceDataBattery.py +22 -22
- modulitiz_micro/rete/http/huawei/fusionsolar/beans/device/DeviceDataPowerSensor.py +49 -49
- modulitiz_micro/rete/http/huawei/fusionsolar/enums/DevTypeIdEnum.py +21 -21
- modulitiz_micro/rete/http/huawei/fusionsolar/exceptions/ExceptionTooManyLogins.py +7 -7
- modulitiz_micro/rete/http/huawei/fusionsolar/service/AbstractHuaweiFusionSolar.py +72 -72
- modulitiz_micro/rete/ntp/AbstractModuloNtp.py +73 -73
- modulitiz_micro/rete/ntp/ModuloNtpIt.py +8 -8
- modulitiz_micro/rete/socketserver/AbstractBasicGetSocketServer.py +35 -35
- modulitiz_micro/rete/socketserver/AbstractSocketServer.py +267 -267
- modulitiz_micro/rete/ssl/ModuloSsl.py +56 -56
- modulitiz_micro/sistema/ModuloEnvVars.py +34 -34
- modulitiz_micro/sistema/ModuloSystemPipe.py +67 -67
- modulitiz_micro/social/telegram/AbstractModuloTelegram.py +53 -53
- modulitiz_micro/social/telegram/ModuloTelegramSimple.py +26 -26
- modulitiz_micro/util/beans/globalvar/AbstractBasicGlobalVarBean.py +15 -15
- modulitiz_micro/util/scheduler/ModuleScheduler.py +26 -26
- modulitiz_micro/weather/AbstractModuleWeather.py +31 -31
- modulitiz_micro/weather/ModuleWeather.py +62 -62
- {modulitiz_micro-2.45.0.dist-info → modulitiz_micro-2.46.0.dist-info}/METADATA +59 -59
- modulitiz_micro-2.46.0.dist-info/RECORD +67 -0
- {modulitiz_micro-2.45.0.dist-info → modulitiz_micro-2.46.0.dist-info}/licenses/LICENSE +21 -21
- modulitiz_micro-2.45.0.dist-info/RECORD +0 -66
- {modulitiz_micro-2.45.0.dist-info → modulitiz_micro-2.46.0.dist-info}/WHEEL +0 -0
- {modulitiz_micro-2.45.0.dist-info → modulitiz_micro-2.46.0.dist-info}/top_level.txt +0 -0
@@ -1,26 +1,26 @@
|
|
1
|
-
from functools import wraps
|
2
|
-
|
3
|
-
from cachetools import TTLCache
|
4
|
-
from cachetools import cached
|
5
|
-
|
6
|
-
from modulitiz_nano.ModuloNumeri import ModuloNumeri
|
7
|
-
|
8
|
-
|
9
|
-
def cacheRam(minsBeforeExpiry: int|float|None):
|
10
|
-
"""
|
11
|
-
Usare questo decorator per mettere in cache delle informazioni.
|
12
|
-
Alla base usa una libreria di terze parti.
|
13
|
-
:param minsBeforeExpiry: se null mantiene i dati in memoria per 1 giorno
|
14
|
-
"""
|
15
|
-
|
16
|
-
__secsBeforeExpiry=24*3600 if minsBeforeExpiry is None else ModuloNumeri.decimalNumbersTruncate(minsBeforeExpiry*60,2)
|
17
|
-
__cache=cached(TTLCache(20,__secsBeforeExpiry))
|
18
|
-
|
19
|
-
def decorator(funzione):
|
20
|
-
__funzione=__cache(funzione)
|
21
|
-
|
22
|
-
@wraps(funzione)
|
23
|
-
def wrapped(*args,**kwargs):
|
24
|
-
return __funzione(*args,**kwargs)
|
25
|
-
return wrapped
|
26
|
-
return decorator
|
1
|
+
from functools import wraps
|
2
|
+
|
3
|
+
from cachetools import TTLCache
|
4
|
+
from cachetools import cached
|
5
|
+
|
6
|
+
from modulitiz_nano.ModuloNumeri import ModuloNumeri
|
7
|
+
|
8
|
+
|
9
|
+
def cacheRam(minsBeforeExpiry: int|float|None):
|
10
|
+
"""
|
11
|
+
Usare questo decorator per mettere in cache delle informazioni.
|
12
|
+
Alla base usa una libreria di terze parti.
|
13
|
+
:param minsBeforeExpiry: se null mantiene i dati in memoria per 1 giorno
|
14
|
+
"""
|
15
|
+
|
16
|
+
__secsBeforeExpiry=24*3600 if minsBeforeExpiry is None else ModuloNumeri.decimalNumbersTruncate(minsBeforeExpiry*60,2)
|
17
|
+
__cache=cached(TTLCache(20,__secsBeforeExpiry))
|
18
|
+
|
19
|
+
def decorator(funzione):
|
20
|
+
__funzione=__cache(funzione)
|
21
|
+
|
22
|
+
@wraps(funzione)
|
23
|
+
def wrapped(*args,**kwargs):
|
24
|
+
return __funzione(*args,**kwargs)
|
25
|
+
return wrapped
|
26
|
+
return decorator
|
@@ -1,28 +1,28 @@
|
|
1
|
-
import git
|
2
|
-
|
3
|
-
from modulitiz_micro.files.git.decorators.catchAndRaiseGitExceptions import catchAndRaiseGitExceptions
|
4
|
-
|
5
|
-
|
6
|
-
class ModuloGit(object):
|
7
|
-
def __init__(self, repoPath:str):
|
8
|
-
self.inner=git.Repo(repoPath)
|
9
|
-
|
10
|
-
@catchAndRaiseGitExceptions
|
11
|
-
def getWorkingCopyRevision(self)->str:
|
12
|
-
return self.inner.head.object.hexsha
|
13
|
-
|
14
|
-
@catchAndRaiseGitExceptions
|
15
|
-
def getRemoteRevision(self)->str:
|
16
|
-
return self.inner.remotes[0].fetch()[0].ref.object.hexsha
|
17
|
-
|
18
|
-
@catchAndRaiseGitExceptions
|
19
|
-
def addFile(self,filenamePath:str):
|
20
|
-
self.inner.index.add(filenamePath)
|
21
|
-
|
22
|
-
@catchAndRaiseGitExceptions
|
23
|
-
def removeFile(self,filenamePath:str):
|
24
|
-
self.inner.index.remove(filenamePath,working_tree=True)
|
25
|
-
|
26
|
-
@catchAndRaiseGitExceptions
|
27
|
-
def update(self)->str:
|
28
|
-
return self.inner.remotes[0].pull()[0].ref.object.hexsha
|
1
|
+
import git
|
2
|
+
|
3
|
+
from modulitiz_micro.files.git.decorators.catchAndRaiseGitExceptions import catchAndRaiseGitExceptions
|
4
|
+
|
5
|
+
|
6
|
+
class ModuloGit(object):
|
7
|
+
def __init__(self, repoPath:str):
|
8
|
+
self.inner=git.Repo(repoPath)
|
9
|
+
|
10
|
+
@catchAndRaiseGitExceptions
|
11
|
+
def getWorkingCopyRevision(self)->str:
|
12
|
+
return self.inner.head.object.hexsha
|
13
|
+
|
14
|
+
@catchAndRaiseGitExceptions
|
15
|
+
def getRemoteRevision(self)->str:
|
16
|
+
return self.inner.remotes[0].fetch()[0].ref.object.hexsha
|
17
|
+
|
18
|
+
@catchAndRaiseGitExceptions
|
19
|
+
def addFile(self,filenamePath:str):
|
20
|
+
self.inner.index.add(filenamePath)
|
21
|
+
|
22
|
+
@catchAndRaiseGitExceptions
|
23
|
+
def removeFile(self,filenamePath:str):
|
24
|
+
self.inner.index.remove(filenamePath,working_tree=True)
|
25
|
+
|
26
|
+
@catchAndRaiseGitExceptions
|
27
|
+
def update(self)->str:
|
28
|
+
return self.inner.remotes[0].pull()[0].ref.object.hexsha
|
@@ -1,19 +1,19 @@
|
|
1
|
-
from functools import wraps
|
2
|
-
|
3
|
-
from git import GitCommandError
|
4
|
-
|
5
|
-
from modulitiz_micro.files.git.exceptions.EccezioneGit import EccezioneGit
|
6
|
-
|
7
|
-
|
8
|
-
def catchAndRaiseGitExceptions(funzione):
|
9
|
-
"""
|
10
|
-
Cattura tutte le eccezioni git di vario tipo e rilancia un'eccezione custom
|
11
|
-
"""
|
12
|
-
|
13
|
-
@wraps(funzione)
|
14
|
-
def wrapped(*args,**kwargs):
|
15
|
-
try:
|
16
|
-
return funzione(*args,**kwargs)
|
17
|
-
except (GitCommandError,) as ex:
|
18
|
-
raise EccezioneGit() from ex
|
19
|
-
return wrapped
|
1
|
+
from functools import wraps
|
2
|
+
|
3
|
+
from git import GitCommandError
|
4
|
+
|
5
|
+
from modulitiz_micro.files.git.exceptions.EccezioneGit import EccezioneGit
|
6
|
+
|
7
|
+
|
8
|
+
def catchAndRaiseGitExceptions(funzione):
|
9
|
+
"""
|
10
|
+
Cattura tutte le eccezioni git di vario tipo e rilancia un'eccezione custom
|
11
|
+
"""
|
12
|
+
|
13
|
+
@wraps(funzione)
|
14
|
+
def wrapped(*args,**kwargs):
|
15
|
+
try:
|
16
|
+
return funzione(*args,**kwargs)
|
17
|
+
except (GitCommandError,) as ex:
|
18
|
+
raise EccezioneGit() from ex
|
19
|
+
return wrapped
|
@@ -1,7 +1,7 @@
|
|
1
|
-
from modulitiz_nano.eccezioni.EccezioneBase import EccezioneBase
|
2
|
-
|
3
|
-
|
4
|
-
class EccezioneGit(EccezioneBase):
|
5
|
-
|
6
|
-
def __init__(self,*args,**kwargs):
|
7
|
-
super().__init__(*args,**kwargs)
|
1
|
+
from modulitiz_nano.eccezioni.EccezioneBase import EccezioneBase
|
2
|
+
|
3
|
+
|
4
|
+
class EccezioneGit(EccezioneBase):
|
5
|
+
|
6
|
+
def __init__(self,*args,**kwargs):
|
7
|
+
super().__init__(*args,**kwargs)
|
@@ -1,44 +1,44 @@
|
|
1
|
-
from bs4 import BeautifulSoup
|
2
|
-
|
3
|
-
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
4
|
-
from modulitiz_nano.files.ModuloFiles import ModuloFiles
|
5
|
-
|
6
|
-
|
7
|
-
class GestioneDom(object):
|
8
|
-
def __init__(self, percorsoNomefile: str | None, htmlString:str):
|
9
|
-
if percorsoNomefile is not None:
|
10
|
-
self.percorsoNomefile=percorsoNomefile
|
11
|
-
htmlString=ModuloFiles.readFileText(percorsoNomefile, True)
|
12
|
-
self.htmlString=htmlString
|
13
|
-
self.dom=self.__createObj()
|
14
|
-
|
15
|
-
@staticmethod
|
16
|
-
def innerHTML(tag):
|
17
|
-
"""
|
18
|
-
dato in input un tag html della classe BeautifulSoup, restituisce il codice html all'interno di questo tag
|
19
|
-
"""
|
20
|
-
return "".join([str(x) for x in tag.contents])
|
21
|
-
|
22
|
-
def selector(self,cssSelector:str):
|
23
|
-
"""
|
24
|
-
estrae tutti gli elementi che corrispondono al css selector
|
25
|
-
"""
|
26
|
-
elementi=self.dom.select(cssSelector)
|
27
|
-
return elementi
|
28
|
-
|
29
|
-
@staticmethod
|
30
|
-
def getAttributeValue(tag, nomeAttr:str):
|
31
|
-
oldValue=tag.attrs[nomeAttr]
|
32
|
-
return oldValue
|
33
|
-
@staticmethod
|
34
|
-
def setAttributeValue(tag, nomeAttr:str, value):
|
35
|
-
tag.attrs[nomeAttr]=value
|
36
|
-
return tag
|
37
|
-
|
38
|
-
def save(self):
|
39
|
-
htmlOut=str(self.dom).encode(ModuloStringhe.CODIFICA_UTF8)
|
40
|
-
with ModuloFiles.open(self.percorsoNomefile, "wb") as file:
|
41
|
-
file.write(htmlOut)
|
42
|
-
|
43
|
-
def __createObj(self)->BeautifulSoup:
|
44
|
-
return BeautifulSoup(self.htmlString, features="html.parser")
|
1
|
+
from bs4 import BeautifulSoup
|
2
|
+
|
3
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
4
|
+
from modulitiz_nano.files.ModuloFiles import ModuloFiles
|
5
|
+
|
6
|
+
|
7
|
+
class GestioneDom(object):
|
8
|
+
def __init__(self, percorsoNomefile: str | None, htmlString:str):
|
9
|
+
if percorsoNomefile is not None:
|
10
|
+
self.percorsoNomefile=percorsoNomefile
|
11
|
+
htmlString=ModuloFiles.readFileText(percorsoNomefile, True)
|
12
|
+
self.htmlString=htmlString
|
13
|
+
self.dom=self.__createObj()
|
14
|
+
|
15
|
+
@staticmethod
|
16
|
+
def innerHTML(tag):
|
17
|
+
"""
|
18
|
+
dato in input un tag html della classe BeautifulSoup, restituisce il codice html all'interno di questo tag
|
19
|
+
"""
|
20
|
+
return "".join([str(x) for x in tag.contents])
|
21
|
+
|
22
|
+
def selector(self,cssSelector:str):
|
23
|
+
"""
|
24
|
+
estrae tutti gli elementi che corrispondono al css selector
|
25
|
+
"""
|
26
|
+
elementi=self.dom.select(cssSelector)
|
27
|
+
return elementi
|
28
|
+
|
29
|
+
@staticmethod
|
30
|
+
def getAttributeValue(tag, nomeAttr:str):
|
31
|
+
oldValue=tag.attrs[nomeAttr]
|
32
|
+
return oldValue
|
33
|
+
@staticmethod
|
34
|
+
def setAttributeValue(tag, nomeAttr:str, value):
|
35
|
+
tag.attrs[nomeAttr]=value
|
36
|
+
return tag
|
37
|
+
|
38
|
+
def save(self):
|
39
|
+
htmlOut=str(self.dom).encode(ModuloStringhe.CODIFICA_UTF8)
|
40
|
+
with ModuloFiles.open(self.percorsoNomefile, "wb") as file:
|
41
|
+
file.write(htmlOut)
|
42
|
+
|
43
|
+
def __createObj(self)->BeautifulSoup:
|
44
|
+
return BeautifulSoup(self.htmlString, features="html.parser")
|
@@ -1,62 +1,62 @@
|
|
1
|
-
from modulitiz_nano.ModuloNumeri import ModuloNumeri
|
2
|
-
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
3
|
-
from modulitiz_nano.eccezioni.EccezioneRuntime import EccezioneRuntime
|
4
|
-
from modulitiz_micro.eccezioni.http.EccezioneHttp import EccezioneHttp
|
5
|
-
from modulitiz_nano.files.ModuloLogging import ModuloLogging
|
6
|
-
from modulitiz_micro.iot.beans.IotDeviceBean import IotDeviceBean
|
7
|
-
from modulitiz_micro.iot.enums.IotOSEnum import IotOSEnum
|
8
|
-
from modulitiz_micro.iot.espurna.ModuleEspurna import ModuleEspurna
|
9
|
-
from modulitiz_micro.rete.http.ModuloHttp import ModuloHttp
|
10
|
-
|
11
|
-
|
12
|
-
class ModuleIotDevice(object):
|
13
|
-
def __init__(self, logger:ModuloLogging|None, deviceBean:IotDeviceBean):
|
14
|
-
self.__logger=logger
|
15
|
-
self.__deviceBean=deviceBean
|
16
|
-
|
17
|
-
def getRelayStatus(self, relayNum:int)->bool:
|
18
|
-
"""
|
19
|
-
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
20
|
-
"""
|
21
|
-
if self.__deviceBean.os==IotOSEnum.ESPURNA:
|
22
|
-
url=ModuleEspurna.URL_GET_RELAY.format(ip=self.__deviceBean.ip,relayNum=relayNum,apiKey=self.__deviceBean.key)
|
23
|
-
else:
|
24
|
-
raise EccezioneRuntime("Iot os '%s' not known"%(self.__deviceBean.os,))
|
25
|
-
return ModuloNumeri.intToBool(ModuloNumeri.strToInt(self.__sendRequest(url)))
|
26
|
-
|
27
|
-
def setRelayStatus(self,relayNum: int,status: bool):
|
28
|
-
"""
|
29
|
-
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
30
|
-
@param status: value to set, can only be false or true
|
31
|
-
"""
|
32
|
-
self.__setRelayStatus(relayNum,status)
|
33
|
-
|
34
|
-
def setRelayStatusToggle(self,relayNum: int):
|
35
|
-
self.__setRelayStatus(relayNum,None)
|
36
|
-
|
37
|
-
def __setRelayStatus(self, relayNum:int, status:bool|None):
|
38
|
-
"""
|
39
|
-
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
40
|
-
@param status: value to set, can be: false = off, true = on, null/None = toggle
|
41
|
-
"""
|
42
|
-
if self.__deviceBean.os==IotOSEnum.ESPURNA:
|
43
|
-
if status is not None:
|
44
|
-
statusStr=str(ModuloNumeri.boolToInt(status))
|
45
|
-
else:
|
46
|
-
statusStr=2
|
47
|
-
url=ModuleEspurna.URL_SET_RELAY.format(ip=self.__deviceBean.ip,relayNum=relayNum,apiKey=self.__deviceBean.key,status=statusStr)
|
48
|
-
else:
|
49
|
-
raise EccezioneRuntime("Iot os '%s' not known"%(self.__deviceBean.os,))
|
50
|
-
# check output
|
51
|
-
statusOutput=ModuloNumeri.intToBool(int(self.__sendRequest(url)))
|
52
|
-
if status is None or status==statusOutput:
|
53
|
-
return
|
54
|
-
raise EccezioneRuntime("Wrong expected status: %d != %d"%(status,statusOutput))
|
55
|
-
|
56
|
-
def __sendRequest(self, url:str)->str:
|
57
|
-
http=ModuloHttp(url,self.__logger,False)
|
58
|
-
http.setUserAgent()
|
59
|
-
bean=http.doGet(0, False)
|
60
|
-
if bean.status!=ModuloHttp.STATUS_OK:
|
61
|
-
raise EccezioneHttp(bean.status)
|
62
|
-
return bean.responseBody.decode(ModuloStringhe.CODIFICA_UTF8)
|
1
|
+
from modulitiz_nano.ModuloNumeri import ModuloNumeri
|
2
|
+
from modulitiz_nano.ModuloStringhe import ModuloStringhe
|
3
|
+
from modulitiz_nano.eccezioni.EccezioneRuntime import EccezioneRuntime
|
4
|
+
from modulitiz_micro.eccezioni.http.EccezioneHttp import EccezioneHttp
|
5
|
+
from modulitiz_nano.files.ModuloLogging import ModuloLogging
|
6
|
+
from modulitiz_micro.iot.beans.IotDeviceBean import IotDeviceBean
|
7
|
+
from modulitiz_micro.iot.enums.IotOSEnum import IotOSEnum
|
8
|
+
from modulitiz_micro.iot.espurna.ModuleEspurna import ModuleEspurna
|
9
|
+
from modulitiz_micro.rete.http.ModuloHttp import ModuloHttp
|
10
|
+
|
11
|
+
|
12
|
+
class ModuleIotDevice(object):
|
13
|
+
def __init__(self, logger:ModuloLogging|None, deviceBean:IotDeviceBean):
|
14
|
+
self.__logger=logger
|
15
|
+
self.__deviceBean=deviceBean
|
16
|
+
|
17
|
+
def getRelayStatus(self, relayNum:int)->bool:
|
18
|
+
"""
|
19
|
+
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
20
|
+
"""
|
21
|
+
if self.__deviceBean.os==IotOSEnum.ESPURNA:
|
22
|
+
url=ModuleEspurna.URL_GET_RELAY.format(ip=self.__deviceBean.ip,relayNum=relayNum,apiKey=self.__deviceBean.key)
|
23
|
+
else:
|
24
|
+
raise EccezioneRuntime("Iot os '%s' not known"%(self.__deviceBean.os,))
|
25
|
+
return ModuloNumeri.intToBool(ModuloNumeri.strToInt(self.__sendRequest(url)))
|
26
|
+
|
27
|
+
def setRelayStatus(self,relayNum: int,status: bool):
|
28
|
+
"""
|
29
|
+
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
30
|
+
@param status: value to set, can only be false or true
|
31
|
+
"""
|
32
|
+
self.__setRelayStatus(relayNum,status)
|
33
|
+
|
34
|
+
def setRelayStatusToggle(self,relayNum: int):
|
35
|
+
self.__setRelayStatus(relayNum,None)
|
36
|
+
|
37
|
+
def __setRelayStatus(self, relayNum:int, status:bool|None):
|
38
|
+
"""
|
39
|
+
@param relayNum: Depending on which OS you choose, can be relative (0, 1, ...) or GPIO
|
40
|
+
@param status: value to set, can be: false = off, true = on, null/None = toggle
|
41
|
+
"""
|
42
|
+
if self.__deviceBean.os==IotOSEnum.ESPURNA:
|
43
|
+
if status is not None:
|
44
|
+
statusStr=str(ModuloNumeri.boolToInt(status))
|
45
|
+
else:
|
46
|
+
statusStr=2
|
47
|
+
url=ModuleEspurna.URL_SET_RELAY.format(ip=self.__deviceBean.ip,relayNum=relayNum,apiKey=self.__deviceBean.key,status=statusStr)
|
48
|
+
else:
|
49
|
+
raise EccezioneRuntime("Iot os '%s' not known"%(self.__deviceBean.os,))
|
50
|
+
# check output
|
51
|
+
statusOutput=ModuloNumeri.intToBool(int(self.__sendRequest(url)))
|
52
|
+
if status is None or status==statusOutput:
|
53
|
+
return
|
54
|
+
raise EccezioneRuntime("Wrong expected status: %d != %d"%(status,statusOutput))
|
55
|
+
|
56
|
+
def __sendRequest(self, url:str)->str:
|
57
|
+
http=ModuloHttp(url,self.__logger,False)
|
58
|
+
http.setUserAgent()
|
59
|
+
bean=http.doGet(0, False)
|
60
|
+
if bean.status!=ModuloHttp.STATUS_OK:
|
61
|
+
raise EccezioneHttp(bean.status)
|
62
|
+
return bean.responseBody.decode(ModuloStringhe.CODIFICA_UTF8)
|
@@ -1,7 +1,7 @@
|
|
1
|
-
from modulitiz_nano.eccezioni.EccezioneBase import EccezioneBase
|
2
|
-
|
3
|
-
|
4
|
-
class EccezioneKeyLogger(EccezioneBase):
|
5
|
-
|
6
|
-
def __init__(self):
|
7
|
-
super().__init__("Ricevuto comando da tastiera di chiusura programma")
|
1
|
+
from modulitiz_nano.eccezioni.EccezioneBase import EccezioneBase
|
2
|
+
|
3
|
+
|
4
|
+
class EccezioneKeyLogger(EccezioneBase):
|
5
|
+
|
6
|
+
def __init__(self):
|
7
|
+
super().__init__("Ricevuto comando da tastiera di chiusura programma")
|
@@ -1,73 +1,73 @@
|
|
1
|
-
import threading
|
2
|
-
import time
|
3
|
-
from typing import Callable
|
4
|
-
|
5
|
-
from modulitiz_nano.sistema.ModuloSystem import ModuloSystem
|
6
|
-
|
7
|
-
if ModuloSystem.isWindows():
|
8
|
-
from pynput.keyboard import Key, Listener
|
9
|
-
|
10
|
-
|
11
|
-
class ModuloKeylogger(object):
|
12
|
-
IS_AVAILABLE=ModuloSystem.isWindows()
|
13
|
-
EXIT_KEY=None
|
14
|
-
EXIT_KEY_2=None
|
15
|
-
if IS_AVAILABLE:
|
16
|
-
EXIT_KEY=Key.pause
|
17
|
-
EXIT_KEY_2=Key.menu
|
18
|
-
|
19
|
-
__lastKeyPressed=None
|
20
|
-
__numKeyPressed=0
|
21
|
-
__callbackOnKeyPress=None
|
22
|
-
|
23
|
-
@staticmethod
|
24
|
-
def getTasto(key):
|
25
|
-
try:
|
26
|
-
tasto=key.char
|
27
|
-
except AttributeError:
|
28
|
-
tasto=key
|
29
|
-
if tasto is None:
|
30
|
-
return str(key.vk)
|
31
|
-
return str(tasto).replace("Key.","")
|
32
|
-
|
33
|
-
@classmethod
|
34
|
-
def start(cls,callbackOnKeyPress:Callable,runNewProcess:bool):
|
35
|
-
"""
|
36
|
-
Se la liberia non e' disponibile non verra' caricata, ad esempio se usi la cli
|
37
|
-
"""
|
38
|
-
# controllo se e' disponibile
|
39
|
-
if not cls.IS_AVAILABLE:
|
40
|
-
return
|
41
|
-
# lancio gli handler
|
42
|
-
cls.__callbackOnKeyPress=callbackOnKeyPress
|
43
|
-
if runNewProcess is True:
|
44
|
-
processo=threading.Thread(target=cls.__tStartListening,args=(cls.__onKeyPressHandler,cls.__onKeyReleaseHandler),daemon=True)
|
45
|
-
processo.start()
|
46
|
-
return
|
47
|
-
cls.__startListening(cls.__onKeyPressHandler,cls.__onKeyReleaseHandler)
|
48
|
-
|
49
|
-
@staticmethod
|
50
|
-
def __startListening(onKeyPressHandler,onKeyReleaseHandler):
|
51
|
-
with Listener(on_press=onKeyPressHandler,on_release=onKeyReleaseHandler) as listener:
|
52
|
-
listener.join()
|
53
|
-
@classmethod
|
54
|
-
def __tStartListening(cls,onKeyPressHandler,onKeyReleaseHandler):
|
55
|
-
cls.__startListening(onKeyPressHandler,onKeyReleaseHandler)
|
56
|
-
while True:
|
57
|
-
time.sleep(1)
|
58
|
-
|
59
|
-
#
|
60
|
-
#key handlers
|
61
|
-
#
|
62
|
-
@classmethod
|
63
|
-
def __onKeyPressHandler(cls,key):
|
64
|
-
if cls.__lastKeyPressed==key:
|
65
|
-
return
|
66
|
-
cls.__callbackOnKeyPress(key,cls.__numKeyPressed)
|
67
|
-
|
68
|
-
cls.__lastKeyPressed=key
|
69
|
-
cls.__numKeyPressed+=1
|
70
|
-
@classmethod
|
71
|
-
def __onKeyReleaseHandler(cls,key):
|
72
|
-
cls.__lastKeyPressed=None
|
73
|
-
cls.__numKeyPressed-=1
|
1
|
+
import threading
|
2
|
+
import time
|
3
|
+
from typing import Callable
|
4
|
+
|
5
|
+
from modulitiz_nano.sistema.ModuloSystem import ModuloSystem
|
6
|
+
|
7
|
+
if ModuloSystem.isWindows():
|
8
|
+
from pynput.keyboard import Key, Listener
|
9
|
+
|
10
|
+
|
11
|
+
class ModuloKeylogger(object):
|
12
|
+
IS_AVAILABLE=ModuloSystem.isWindows()
|
13
|
+
EXIT_KEY=None
|
14
|
+
EXIT_KEY_2=None
|
15
|
+
if IS_AVAILABLE:
|
16
|
+
EXIT_KEY=Key.pause
|
17
|
+
EXIT_KEY_2=Key.menu
|
18
|
+
|
19
|
+
__lastKeyPressed=None
|
20
|
+
__numKeyPressed=0
|
21
|
+
__callbackOnKeyPress=None
|
22
|
+
|
23
|
+
@staticmethod
|
24
|
+
def getTasto(key):
|
25
|
+
try:
|
26
|
+
tasto=key.char
|
27
|
+
except AttributeError:
|
28
|
+
tasto=key
|
29
|
+
if tasto is None:
|
30
|
+
return str(key.vk)
|
31
|
+
return str(tasto).replace("Key.","")
|
32
|
+
|
33
|
+
@classmethod
|
34
|
+
def start(cls,callbackOnKeyPress:Callable,runNewProcess:bool):
|
35
|
+
"""
|
36
|
+
Se la liberia non e' disponibile non verra' caricata, ad esempio se usi la cli
|
37
|
+
"""
|
38
|
+
# controllo se e' disponibile
|
39
|
+
if not cls.IS_AVAILABLE:
|
40
|
+
return
|
41
|
+
# lancio gli handler
|
42
|
+
cls.__callbackOnKeyPress=callbackOnKeyPress
|
43
|
+
if runNewProcess is True:
|
44
|
+
processo=threading.Thread(target=cls.__tStartListening,args=(cls.__onKeyPressHandler,cls.__onKeyReleaseHandler),daemon=True)
|
45
|
+
processo.start()
|
46
|
+
return
|
47
|
+
cls.__startListening(cls.__onKeyPressHandler,cls.__onKeyReleaseHandler)
|
48
|
+
|
49
|
+
@staticmethod
|
50
|
+
def __startListening(onKeyPressHandler,onKeyReleaseHandler):
|
51
|
+
with Listener(on_press=onKeyPressHandler,on_release=onKeyReleaseHandler) as listener:
|
52
|
+
listener.join()
|
53
|
+
@classmethod
|
54
|
+
def __tStartListening(cls,onKeyPressHandler,onKeyReleaseHandler):
|
55
|
+
cls.__startListening(onKeyPressHandler,onKeyReleaseHandler)
|
56
|
+
while True:
|
57
|
+
time.sleep(1)
|
58
|
+
|
59
|
+
#
|
60
|
+
#key handlers
|
61
|
+
#
|
62
|
+
@classmethod
|
63
|
+
def __onKeyPressHandler(cls,key):
|
64
|
+
if cls.__lastKeyPressed==key:
|
65
|
+
return
|
66
|
+
cls.__callbackOnKeyPress(key,cls.__numKeyPressed)
|
67
|
+
|
68
|
+
cls.__lastKeyPressed=key
|
69
|
+
cls.__numKeyPressed+=1
|
70
|
+
@classmethod
|
71
|
+
def __onKeyReleaseHandler(cls,key):
|
72
|
+
cls.__lastKeyPressed=None
|
73
|
+
cls.__numKeyPressed-=1
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import asyncio
|
2
|
+
import os.path
|
3
|
+
|
4
|
+
from androidtvremote2 import AndroidTVRemote
|
5
|
+
from androidtvremote2 import CannotConnect
|
6
|
+
from androidtvremote2 import ConnectionClosed
|
7
|
+
from androidtvremote2 import InvalidAuth
|
8
|
+
|
9
|
+
from modulitiz_micro.rete.ModuloNetworking import ModuloNetworking
|
10
|
+
from modulitiz_nano.eccezioni.EccezioneRuntime import EccezioneRuntime
|
11
|
+
from modulitiz_nano.files.ModuloLogging import ModuloLogging
|
12
|
+
from modulitiz_nano.util.decorators.noAwait import noAwait
|
13
|
+
|
14
|
+
|
15
|
+
class ModuleAndroidTVRemote(object):
|
16
|
+
API_PORT=6466
|
17
|
+
PAIR_PORT=6467
|
18
|
+
|
19
|
+
def __init__(self,logger:ModuloLogging,clientName:str,outputDir:str,ip:str):
|
20
|
+
self.__logger=logger
|
21
|
+
self.__clientName=clientName
|
22
|
+
self.__outputDir=outputDir
|
23
|
+
self.__ip=ip
|
24
|
+
|
25
|
+
self.conn:AndroidTVRemote|None=None
|
26
|
+
|
27
|
+
@noAwait
|
28
|
+
async def populate(self):
|
29
|
+
# check availability
|
30
|
+
if not ModuloNetworking.checkPing(self.__ip):
|
31
|
+
raise EccezioneRuntime(f"Ip {self.__ip} not found")
|
32
|
+
self.__isPortOpen(self.API_PORT)
|
33
|
+
self.__isPortOpen(self.API_PORT)
|
34
|
+
# create connection
|
35
|
+
certFile=os.path.join(self.__outputDir,"cert.pem")
|
36
|
+
keyFile=os.path.join(self.__outputDir,"key.pem")
|
37
|
+
self.conn=AndroidTVRemote(self.__clientName,certFile,keyFile,self.__ip)
|
38
|
+
# pairing
|
39
|
+
self.__logger.debug("Start pairing")
|
40
|
+
if await self.conn.async_generate_cert_if_missing():
|
41
|
+
self.__logger.debug("Generated new certificate")
|
42
|
+
await self.__pair()
|
43
|
+
while True:
|
44
|
+
try:
|
45
|
+
await self.conn.async_connect()
|
46
|
+
break
|
47
|
+
except InvalidAuth:
|
48
|
+
self.__logger.exception("Need to pair again")
|
49
|
+
await self.__pair()
|
50
|
+
except (CannotConnect,ConnectionClosed):
|
51
|
+
self.__logger.exception("Cannot connect, exiting")
|
52
|
+
return
|
53
|
+
await asyncio.sleep(0.2)
|
54
|
+
self.__logger.debug("Pair ok")
|
55
|
+
|
56
|
+
async def __pair(self):
|
57
|
+
name,mac=await self.conn.async_get_name_and_mac()
|
58
|
+
self.__logger.info(f"Start Pairing with {self.conn.host} {name} {mac}, this will turn on the Android TV")
|
59
|
+
await self.conn.async_start_pairing()
|
60
|
+
while True:
|
61
|
+
pairing_code=await asyncio.to_thread(input,"Enter pairing code: ")
|
62
|
+
try:
|
63
|
+
return await self.conn.async_finish_pairing(pairing_code)
|
64
|
+
except InvalidAuth:
|
65
|
+
self.__logger.exception("Invalid pairing code")
|
66
|
+
continue
|
67
|
+
except ConnectionClosed:
|
68
|
+
self.__logger.exception("Initialize pair again")
|
69
|
+
await self.__pair()
|
70
|
+
|
71
|
+
def getVolumeLevel(self)->int:
|
72
|
+
return self.conn.volume_info["level"]
|
73
|
+
|
74
|
+
@noAwait
|
75
|
+
async def setVolumeLevel(self,level: int):
|
76
|
+
currentLevel=self.getVolumeLevel()
|
77
|
+
diff=currentLevel-level
|
78
|
+
if diff==0:
|
79
|
+
return
|
80
|
+
cmd="VOLUME_DOWN" if diff>0 else "VOLUME_UP"
|
81
|
+
# pause needed for elaborating data
|
82
|
+
await asyncio.sleep(0.4)
|
83
|
+
for _ in range(abs(diff)):
|
84
|
+
self.conn.send_key_command(cmd)
|
85
|
+
await asyncio.sleep(0.4)
|
86
|
+
# check if level is correct
|
87
|
+
currentLevel=self.getVolumeLevel()
|
88
|
+
if level!=currentLevel:
|
89
|
+
raise EccezioneRuntime(f"Current volume level {currentLevel} don't equals {level}")
|
90
|
+
|
91
|
+
@noAwait
|
92
|
+
async def sendCommand(self,cmd:str):
|
93
|
+
# pause needed for elaborating data
|
94
|
+
await asyncio.sleep(0.4)
|
95
|
+
self.conn.send_key_command(cmd)
|
96
|
+
await asyncio.sleep(0.4)
|
97
|
+
|
98
|
+
def close(self):
|
99
|
+
if self.conn is None:
|
100
|
+
return
|
101
|
+
self.conn.disconnect()
|
102
|
+
self.conn = None
|
103
|
+
|
104
|
+
def __isPortOpen(self,port:int):
|
105
|
+
if ModuloNetworking.isHttpPortOpen(self.__ip,port):
|
106
|
+
return
|
107
|
+
raise EccezioneRuntime(f"Port {port} on ip {self.__ip} not open")
|