From c6f3fcacaeaed2a6e0f611e70b23ddb9c98e8a4f Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 2 Apr 2017 15:07:42 +0300 Subject: [PATCH 1/7] gitignore typetodo --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a0b87d8..2b792e9 100644 --- a/.gitignore +++ b/.gitignore @@ -53,4 +53,6 @@ tmp.py __pycache__ build dist -*.do +*.do.cfg +*.do.state +.gitignore From b25197c753f390bf6a877767405d9992c981edfd Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:37:16 +0300 Subject: [PATCH 2/7] add: handle dropped socket --- yiAPI.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/yiAPI.py b/yiAPI.py index 02bb4a1..033bd24 100644 --- a/yiAPI.py +++ b/yiAPI.py @@ -91,7 +91,11 @@ def cmd(self, _command, _val=None): timeoutCmd= threading.Timer(self.commandTimeout, runCmd.blockingEvent.set) timeoutCmd.start() - self.cmdSend(runCmd.cmdSend) + if not self.cmdSend(runCmd.cmdSend): + logging.critical('Socket error while sending') + + runCmd.blockingEvent.set() + self.sock= None runCmd.blockingEvent.wait() timeoutCmd.cancel() @@ -108,9 +112,14 @@ def cmd(self, _command, _val=None): def cmdSend(self, _cmdDict): logging.debug("Send %s" % _cmdDict) - self.sock.sendall( bytes(json.dumps(_cmdDict),'ascii') ) + try: + self.sock.sendall( bytes(json.dumps(_cmdDict),'ascii') ) + except: + return self.tick+= 1 + return True + def setCB(self, _type=None, _cb=None): From f1fe3f62b3fb554ca3acace1c967e3148f67f928 Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:39:15 +0300 Subject: [PATCH 3/7] add: handle string value appending to params --- yiAPICommand.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/yiAPICommand.py b/yiAPICommand.py index 6b41861..0a50c22 100644 --- a/yiAPICommand.py +++ b/yiAPICommand.py @@ -15,7 +15,8 @@ dict of non-changing parameters. variable - name or list of names to be assigned later with apply() + name or list of names to be assigned later with makeCmd(). + If variable is defined in params as string, it's appended. ''' class YiAPICommandGen(): resultReq= None @@ -44,7 +45,7 @@ def __init__(self, if params: self.params.update(params) - if not isinstance(variable, list) and not isinstance(variable, tuple): + if not isinstance(variable, (list, tuple)): variable= [variable] self.variable= variable @@ -75,7 +76,11 @@ def makeCmd(self, _cmdPrep, _val=None): _val= [_val] for pair in zip(self.variable,_val): - _cmdPrep[pair[0]]= pair[1] + if pair[0] in _cmdPrep and isinstance(_cmdPrep[pair[0]], str): + if isinstance(pair[1], str): + _cmdPrep[pair[0]]+= pair[1] + else: + _cmdPrep[pair[0]]= pair[1] return YiAPICommand(_cmdPrep, self.resultReq, self.resultCB) From 12df0965fde69e26b1399cd312938f18c864565d Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:39:55 +0300 Subject: [PATCH 4/7] fix getFileList and enable deleteFile commands --- __init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/__init__.py b/__init__.py index 599d4a0..13142a2 100644 --- a/__init__.py +++ b/__init__.py @@ -1,18 +1,15 @@ ''' -Lightweighted version of Yi4k API, reverse-engineered from official Java API. -It is limited so: - - values provided to commands should be correct strings, - - camera data exchanging operations are blocking, - - no callbacks are supported. +Lightweighted version of Yi4k API, based on official Java API. +Values provided to commands should be correct strings. + +deleteFile and getFileList commands require path relative to DCIM folder. +deleteFile though could be unsafe by supplying '..' path. Commands not implemented: formatSDCard NSFW - deleteFile - Considered vulnerable, maybe later - downloadFile cancelDownload Redundant, available by http @@ -24,8 +21,7 @@ Maybe later startRecording datetime - Lazy to implement - + Lazy to implement, due to different input value format ''' @@ -48,11 +44,15 @@ ) getFileList= YiAPICommandGen(1282, 'getFileList', - params= {'param':'/tmp/fuse_d'}, + params= {'param':'/tmp/fuse_d/DCIM/'}, + variable= 'param', resultCB= lambda res: res['listing'] ) -#deleteFile= YiAPICommandGen(1281, 'deleteFile', {}, {'param': '/tmp/fuse_d/DCIM'}, resultCB= lambda res: res['listing']) +deleteFile= YiAPICommandGen(1281, 'deleteFile', + params= {'param':'/tmp/fuse_d/DCIM/'}, + variable= 'param' +) startViewFinder= YiAPICommandGen(259, 'startViewFinder') stopViewFinder= YiAPICommandGen(260, 'stopViewFinder') From 06f79bd69a0986584d4a431d32c71576c60c24f2 Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:40:54 +0300 Subject: [PATCH 5/7] test: add deleteFile case --- test/testApi.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/testApi.py b/test/testApi.py index 0162d89..8d334b5 100644 --- a/test/testApi.py +++ b/test/testApi.py @@ -32,8 +32,8 @@ def set_ok(_res): print('getSettings: %s' % str(res)) res= a.cmd(stopRecording) print('(err:stopped) stopRecording: %s' % str(res)) -time.sleep(40) -print('=============Paused to test manual recording tart/stop and shange settings') +print('=============Paused to test manual recording start/stop and shange settings') +time.sleep(20) print('') @@ -49,6 +49,8 @@ def set_ok(_res): res= a.cmd(stopRecording) print('stopRecording: %s' % str(res)) +res= a.cmd(deleteFile, str(res).split('/tmp/fuse_d/DCIM/')[1]) +print('deleted: %s' % str(res)) res= a.cmd(setVideoExposureValue, resEv) print('setVideoExposureValue: %s' % str(res)) time.sleep(4) From aa152e0a05fb863ce8885559862960543e23d051 Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:43:15 +0300 Subject: [PATCH 6/7] todo and cleanup --- Yi4kAPI.do | 27 +++++++++++++++++++++++++++ yiAPIListener.py | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Yi4kAPI.do diff --git a/Yi4kAPI.do b/Yi4kAPI.do new file mode 100644 index 0000000..6540e22 --- /dev/null +++ b/Yi4kAPI.do @@ -0,0 +1,27 @@ +-feature 1: +0 "yiClasses.py" kii 17/01/12 17:35:58 + add error constants + + feature 2: +0 "yiClasses.py" kii 17/01/12 21:23:35 + implement nonblocking execution, use callbacks + +!feature 3: +0 "yiClasses.py" kii 17/05/21 04:42:41 + predefined limit of supplied variables + +!feature 4: +0 "" kii 17/01/15 05:17:26 + redundant + +!feature 5: +0 "yiClasses.py" kii 17/04/02 15:11:56 + continously recieve result + ++ux 6: +0 "__init__.py" kii 17/05/21 04:41:47 + add sample usecase + ++ 8: +0 "" kii 17/05/21 04:41:19 + detect disconnect + ++check 9: +0 "yiAPI.py" kii 17/05/21 04:41:21 + test if disconnected + ++fix 10: +0 "__init__.py" kii 17/05/21 04:41:44 + getFileList not listing all files + diff --git a/yiAPIListener.py b/yiAPIListener.py index bc3de20..a668a4f 100644 --- a/yiAPIListener.py +++ b/yiAPIListener.py @@ -3,7 +3,7 @@ ''' -Constantly listen to opened Yi4k camera for sultable response. +Constantly listen to opened Yi4k camera for suitable response. Most of response will be the result of commands sent to camera, while some of the responce is camera state, pushed periodically. ''' From c4b302ac1e6b52928ee0c356c3ffa015a9b67a7f Mon Sep 17 00:00:00 2001 From: NikolayRag Date: Sun, 21 May 2017 04:48:58 +0300 Subject: [PATCH 7/7] readme and changelog --- README.md | 6 ++---- __init__.py | 2 +- changelog.txt | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b6f5e73..5e8f6a6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Differences from original API: - 'stopRecording' and 'capturePhoto' waits till operation is really ended and return produced file name. - Values provided to commands should be correct strings, compared to integers in original API. - 'adapter', 'adapter_status' and 'battery_status' callbacks are available in addition to all other. .setCB() used to set/get callbacks. +- 'deleteFile' and 'getFileList' commands require path relative to DCIM folder. Try not to call same commands simultaneously from different threads: camera response is not clearly identified with caller and response can be mixed. @@ -15,9 +16,6 @@ Try not to call same commands simultaneously from different threads: camera resp - formatSDCard NSFW -- deleteFile - Considered vulnerable, maybe later - - downloadFile - cancelDownload Redundant, available by http @@ -29,4 +27,4 @@ Try not to call same commands simultaneously from different threads: camera resp Maybe later - startRecording datetime - Lazy to implement + Lazy to implement due to specific input value format diff --git a/__init__.py b/__init__.py index 13142a2..ebc185e 100644 --- a/__init__.py +++ b/__init__.py @@ -21,7 +21,7 @@ Maybe later startRecording datetime - Lazy to implement, due to different input value format + Lazy to implement due to specific input value format ''' diff --git a/changelog.txt b/changelog.txt index 7e7d46b..224b2f1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +v1.4 + add: + - handle connection loss + - deleteFile command, path is relative to DCIM folder + fix: + - getFileList accepts path relative to DCIM folder + v1.3 add: - 'start_album' and 'stop_album' events.