From e3481a58adc600845609893ca4b0d1b180bda295 Mon Sep 17 00:00:00 2001 From: Ruben van de Ven Date: Thu, 28 Nov 2019 16:21:00 +0100 Subject: [PATCH] isSophie checkbox for light, and lightmap which is stored acros runs --- hugvey/central_command.py | 57 +++++++++++++++++++++++----- hugvey/panopticon.py | 5 ++- hugvey/story.py | 14 +++++-- hugvey_server.py | 12 ++++-- www/css/styles.css | 5 ++- www/js/crel.min.js | 6 +++ www/js/hugvey_console.js | 67 ++++++++++++++++++++++++++++++++- www/panopticon.html | 79 +++++++++++++++++++-------------------- www/scss/styles.scss | 4 ++ 9 files changed, 189 insertions(+), 60 deletions(-) diff --git a/hugvey/central_command.py b/hugvey/central_command.py index 0d5c33c..f604028 100644 --- a/hugvey/central_command.py +++ b/hugvey/central_command.py @@ -76,6 +76,9 @@ class CentralCommand(object): self.timer = Stopwatch() self.hugveyWarnings = {} + + self.lightMapFile = os.path.join('state','lightMap.json') + self.lightMap = {} eventLogger.addHandler(logging.handlers.QueueHandler(self.logQueue)) @@ -92,10 +95,10 @@ class CentralCommand(object): self.config[arg] = getattr(self.args,arg) self.hugvey_ids = [i + 1 for i in range(self.config['hugveys'])] + self.loadLightMap() self.loadLanguages() - voice_dir = os.path.join(self.config['web']['files_dir'], 'voices') self.voiceStorage = VoiceStorage(voice_dir, self.languageConfig) varDb = os.path.join( @@ -133,7 +136,26 @@ class CentralCommand(object): self.languageConfig[lang['code']] = lang with open(lang_filename, 'r') as fp: self.languages[lang['code']] = json.load(fp) - + + def loadLightMap(self): + if os.path.exists(self.lightMapFile): + with open(self.lightMapFile) as fp: + lightMap = json.load(fp) + #json only has string keys, we want integers (not using pickle for human readability) + self.lightMap = {int(k): v for k,v in lightMap.items()} + logger.info(f"Loaded light mapping from {self.lightMapFile}") + for hv_id in self.hugvey_ids: + if hv_id not in self.lightMap: + print(hv_id, self.lightMap) + raise Exception("Invalid light map, not all hugveys are included. Remove lightMap.json") + else: + # by default each hv, has the same nr of light + self.lightMap = {id: id for id in self.hugvey_ids} + + def saveLightMap(self): + with open(self.lightMapFile, 'w') as fp: + json.dump(self.lightMap, fp, indent=4, sort_keys=True) + logger.info(f"Wrote light mapping to {self.lightMapFile}") def getHugveyStatus(self, hv_id, isSelected = False): status = {'id': hv_id} @@ -148,7 +170,7 @@ class CentralCommand(object): #: :type hv: HugveyState status['status'] = hv.getStatus() - status['light_on'] = bool(hv.lightStatus) + status['light'] = hv.lightTransitionStatus status['language'] = hv.language_code status['light_id'] = hv.lightId status['available'] = hv.isAvailable() @@ -199,6 +221,16 @@ class CentralCommand(object): # pass return status + + def setLightForHugvey(self, hv_id, lightId): + if hv_id not in self.lightMap: + logger.critical(f"Try to configure light for non-existing Hugvey {hv_id}") + return + + logger.info(f"Set light for hugvey: {hv_id} to {lightId}") + self.lightMap[hv_id] = lightId + self.hugveys[hv_id].setLightId(lightId) + self.saveLightMap() def getStatusSummary(self, selected_ids = []): status = { @@ -373,6 +405,7 @@ class CentralCommand(object): while self.isRunning.is_set(): logger.info(f'Instantiate hugvey #{hugvey_id}') h = HugveyState(hugvey_id, self) + h.setLightId(self.lightMap[hugvey_id]) # h.config(msg['host'], msg['ip']) self.hugveys[hugvey_id] = h r = h.run() @@ -553,6 +586,7 @@ class HugveyState(object): self.setStatus(self.STATE_GONE) self.requireRestartAfterStop = None + self.lightTransitionStatus = {'intensity': self.command.config['light']['off_intensity'], 'duration': self.command.config['light']['fade_duration_id'], 'isSophie': False} def __del__(self): self.logger.warn("Destroying hugvey object") @@ -793,14 +827,16 @@ class HugveyState(object): self.command.commandLight('/hugvey', [self.lightId, self.lightStatus]) - def transitionLight(self, intensity, duration): + def transitionLight(self, intensity, duration, isSophie = False): """ Intensity: 0-255 duration: an integer between 0-92 indicating the lanbox fade times + The light fade in & out for Sophie (a moment in the story) are an override, so that + they come in even though all is out. """ - self.lightIntensity = intensity - self.logger.debug(f"Send /hugvey_fade {self.lightIntensity} {duration}") - self.command.commandLight('/hugvey_fade', [self.lightId, intensity, int(duration)]) + self.lightTransitionStatus = {'intensity': intensity, 'duration': duration, 'isSophie': isSophie} + self.logger.debug(f"Send /hugvey_fade {intensity} {duration} {1 if isSophie else 0}") + self.command.commandLight('/hugvey_fade', [self.lightId, intensity, int(duration), 1 if isSophie else 0]) def setLightId(self, id): """ @@ -890,8 +926,9 @@ class HugveyState(object): if self.command.config['story']['loop']: if not self.blockRestart: - self.logger.info("Loop story") - self.restart() + if self.notShuttingDown: + self.logger.info("Loop story") + self.restart() else: self.logger.info("Don't loop on manual finish") @@ -914,7 +951,7 @@ class HugveyState(object): self.streamer.addConsumer(self.player) if self.command.config['voice']['record_dir']: - self.logger.warn("Record Audio of conversation") + self.logger.info("Record Audio of conversation") self.recorder = Recorder( self.id, self.command.config['voice']['src_rate'], self.command.config['voice']['record_dir'], self.command.config['voice']['record_voice'] if 'record_voice' in self.command.config['voice'] else False) diff --git a/hugvey/panopticon.py b/hugvey/panopticon.py index 61c5c42..ad959a2 100644 --- a/hugvey/panopticon.py +++ b/hugvey/panopticon.py @@ -169,8 +169,9 @@ def getWebSocketHandler(central_command): central_command.setLoopTime(seconds) def msgChangeLightId(self, hv_id, lightId): - if central_command.hugveys[hv_id].eventQueue: - central_command.hugveys[hv_id].eventQueue.put_nowait({'event': 'change_light', 'light_id': lightId}) + central_command.setLightForHugvey(hv_id, lightId) +# if central_command.hugveys[hv_id].eventQueue: +# central_command.hugveys[hv_id].eventQueue.put_nowait({'event': 'change_light', 'light_id': lightId}) def msgChangeLightStatus(self, hv_id, status): if central_command.hugveys[hv_id].eventQueue: diff --git a/hugvey/story.py b/hugvey/story.py index d94c369..19a211a 100644 --- a/hugvey/story.py +++ b/hugvey/story.py @@ -1166,14 +1166,19 @@ class Configuration(object): time_factor = 1 light0_intensity = 0 light0_fade = 30. # fade duration in seconds + light0_isSophie = False light1_intensity = 150 light1_fade = 10. + light1_isSophie = False light2_intensity = 75 light2_fade = 10. + light2_isSophie = False light3_intensity = 150 light3_fade = 10. + light3_isSophie = False light4_intensity = 150 light4_fade = 10. + light4_isSophie = False @classmethod def initFromJson(configClass, data, story): @@ -1187,7 +1192,8 @@ class Configuration(object): for i in range(5): l.append({ 'intensity': int(c[f"light{i}_intensity"]), - 'fade': float(c[f"light{i}_fade"]) + 'fade': float(c[f"light{i}_fade"]), + 'isSophie': float(c[f"light{i}_isSophie"]) }) return l @@ -1783,7 +1789,7 @@ class Story(object): # Test stability of Central Command with deliberate crash # if self.timer.getElapsed() > 10: # raise Exception("Test exception") - if not self.timer.hasMark('state_save') or self.timer.getElapsed('state_save') > 45: + if not self.timer.hasMark('state_save') or self.timer.getElapsed('state_save') > 30: self.storeState() self.timer.setMark('state_save') @@ -1891,7 +1897,7 @@ class Story(object): preset = self.configuration.getLightPresets()[presetNr] self.currentLightPresetNr = presetNr - self.hugvey.transitionLight(preset['intensity'], preset['fade']) + self.hugvey.transitionLight(preset['intensity'], preset['fade'], preset['isSophie']) def getCurrentDirections(self): if self.currentMessage.id not in self.directionsPerMsg: @@ -2082,6 +2088,7 @@ class Story(object): @classmethod def hugveyHasSavedState(cls, hv_id): +# print(os.path.exists(cls.getStateFilename(hv_id)), cls.getStateFilename(hv_id)) return os.path.exists(cls.getStateFilename(hv_id)) @classmethod @@ -2095,6 +2102,7 @@ class Story(object): story.logger = mainLogger.getChild(f"{story.hugvey.id}").getChild("story") # TODO: this is not really working because it is overridden by the set-status later. # story.hugvey.setLightStatus(story.lightStateSave) + story.logger.critical(f"Light preset {story.currentLightPresetNr}") if story.currentLightPresetNr is not None: story.fadeLightPreset(story.currentLightPresetNr) return story diff --git a/hugvey_server.py b/hugvey_server.py index 3625cbc..8ad29c3 100644 --- a/hugvey_server.py +++ b/hugvey_server.py @@ -60,6 +60,12 @@ if __name__ == '__main__': rootLogger.addHandler(socket_handler) logger.info("Start server") - command = CentralCommand(args=args, debug_mode=args.verbose > 0) - command.loadConfig(args.config) - command.start() + + try: + print('\33]0;Hugvey server\a', end='', flush=True) + command = CentralCommand(args=args, debug_mode=args.verbose > 0) + command.loadConfig(args.config) + command.start() + finally: +# reset terminal title + print('\33]0;\a', end='', flush=True) diff --git a/www/css/styles.css b/www/css/styles.css index 85e6a7a..8060449 100644 --- a/www/css/styles.css +++ b/www/css/styles.css @@ -125,7 +125,10 @@ img.icon { font-weight: normal; position: absolute; left: 5px; - top: 5px; } + top: 5px; + font-size: 150%; } + #status .hugvey h1 .light_id-hv_id { + font-size: 75%; } #status .hugvey .status { font-style: italic; color: gray; diff --git a/www/js/crel.min.js b/www/js/crel.min.js index 4fe1736..9dd52f7 100644 --- a/www/js/crel.min.js +++ b/www/js/crel.min.js @@ -1,5 +1,11 @@ !function(n,e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):n.crel=e()}(this,function(){function n(a){var d,s=arguments,p=s[1],y=2,m=s.length,x=n[o];if(a=n[u](a)?a:c.createElement(a),m>1){if((!e(p,r)||n[f](p)||Array.isArray(p))&&(--y,p=null),m-y==1&&e(s[y],"string"))a.textContent=s[y];else for(;y

- {{ hv.light_id }} (#{{hv.id}}) + {{ hv.light_id }} (#{{hv.id}})

{{ hv.status }}
-
- - {{ hv.language }} - - - - -
-
- - {{c}} -
-
- - {{ hv.msg }} -
-
- - {{ timer(hv, 'duration') }} +
+
+ + {{ hv.language }} + + + + +
+
+ + {{c}} +
+
+ + {{ hv.msg }} +
+
+ + {{ timer(hv, 'duration') }} +
+
Unblock
+
Block
+
Start
+
Finish
+
Pause
+
Resume
+ +
Resume from save
-
Unblock
-
Block
-
Start
-
Finish
-
Pause
-
Resume
- -
Resume from save
-
Light: - +
Intensity: {{hv.light['intensity']}}, Fade #{{hv.light['duration']}} (sophie)
diff --git a/www/scss/styles.scss b/www/scss/styles.scss index 385f16e..80386e6 100644 --- a/www/scss/styles.scss +++ b/www/scss/styles.scss @@ -172,6 +172,10 @@ img.icon{ left: 5px; top: 5px; font-size:150%; + + .light_id-hv_id{ + font-size:75%; + } } .status{