Fix a bug that the story strand 'end-finder' loops infinite, load saved state now uses the light/position id rather than device id, passing a message can trigger the light, and status changes provide cleaner logs

This commit is contained in:
Ruben van de Ven 2019-06-08 16:10:46 +02:00
parent 126c10b5ce
commit 39dbf0502a
3 changed files with 59 additions and 21 deletions

View file

@ -128,7 +128,7 @@ class CentralCommand(object):
# status['counts'] = {t: len(a) for t, a in status['history'].items() if t != 'directions' } # status['counts'] = {t: len(a) for t, a in status['history'].items() if t != 'directions' }
status['counts'] = {} if not hv.story else hv.story.getLogCounts() status['counts'] = {} if not hv.story else hv.story.getLogCounts()
status['duration'] = 0 if not hv.story else hv.story.timer.getElapsed() status['duration'] = 0 if not hv.story else hv.story.timer.getElapsed()
status['has_state'] = Story.hugveyHasSavedState(hv.id) status['has_state'] = Story.hugveyHasSavedState(hv.lightId)
status['variables'] = {} if not isSelected or not hv.story else hv.story.variableValues status['variables'] = {} if not isSelected or not hv.story else hv.story.variableValues
return status return status
@ -456,7 +456,6 @@ class HugveyState(object):
self.setLightStatus(lightOn) self.setLightStatus(lightOn)
self.eventLogger.info(f"status: {self.status}") self.eventLogger.info(f"status: {self.status}")
def config(self, hostname, ip): def config(self, hostname, ip):
self.ip = ip self.ip = ip
self.hostname = hostname self.hostname = hostname
@ -607,8 +606,9 @@ class HugveyState(object):
if self.google: if self.google:
self.google.setLanguage(language_code) self.google.setLanguage(language_code)
def pause(self): def pause(self, log = True):
self.logger.info('Pause') if log:
self.logger.info('Pause')
if self.google: if self.google:
self.google.pause() self.google.pause()
if self.story: if self.story:
@ -616,9 +616,10 @@ class HugveyState(object):
self.isRunning.clear() self.isRunning.clear()
self.setStatus(self.STATE_PAUSE) self.setStatus(self.STATE_PAUSE)
def resume(self): def resume(self, log = True):
"""Start playing without reset, also used to play from a saved state""" """Start playing without reset, also used to play from a saved state"""
self.logger.info('Resume') if log:
self.logger.info('Resume')
if self.google: if self.google:
self.google.resume() self.google.resume()
if self.story: if self.story:
@ -629,11 +630,11 @@ class HugveyState(object):
def restart(self): def restart(self):
"""Start playing with reset""" """Start playing with reset"""
self.logger.info('Restart') self.logger.info('Restart')
if Story.hugveyHasSavedState(self.id): if Story.hugveyHasSavedState(self.lightId):
Story.clearSavedState(self.id) Story.clearSavedState(self.lightId)
if self.story: if self.story:
self.story.stop() self.story.stop()
self.resume() self.resume(log=False)
def block(self): def block(self):
"""Block a hugvey""" """Block a hugvey"""
@ -648,7 +649,8 @@ class HugveyState(object):
def available(self): def available(self):
"""Put in available mode""" """Put in available mode"""
self.logger.info('Finish/Await') self.logger.info('Finish/Await')
self.pause() # TODO: Toggle running if config says so, but turn light on
self.pause(log=False)
self.setStatus(self.STATE_AVAILABLE) self.setStatus(self.STATE_AVAILABLE)
def setLightStatus(self, on): def setLightStatus(self, on):
@ -666,7 +668,7 @@ class HugveyState(object):
def gone(self): def gone(self):
'''Status to 'gone' as in, shutdown/crashed/whatever '''Status to 'gone' as in, shutdown/crashed/whatever
''' '''
self.pause() self.pause(log=False)
if self.story: if self.story:
self.story.stop() self.story.stop()

View file

@ -71,6 +71,7 @@ class Message(object):
self.parseForVariables() self.parseForVariables()
self.uuid = None # Have a unique id each time the message is played back. self.uuid = None # Have a unique id each time the message is played back.
self.color = None self.color = None
self.lightChange = None
def __getstate__(self): def __getstate__(self):
# Copy the object's state from self.__dict__ which contains # Copy the object's state from self.__dict__ which contains
@ -106,6 +107,7 @@ class Message(object):
if not 'vol' in msg.params: if not 'vol' in msg.params:
# prevent clipping on some Lyrebird tracks # prevent clipping on some Lyrebird tracks
msg.params['vol'] = .8 msg.params['vol'] = .8
msg.lightChange = data['light'] if 'light' in data else None
msg.params['vol'] = float(msg.params['vol']) msg.params['vol'] = float(msg.params['vol'])
@ -1577,6 +1579,9 @@ class Story(object):
'params': params, 'params': params,
'duration': duration 'duration': duration
}) })
if message.lightChange is not None:
self.hugvey.setLightStatus(message.lightChange)
# 2019-02-22 temporary disable listening while playing audio: # 2019-02-22 temporary disable listening while playing audio:
# if self.hugvey.google is not None: # if self.hugvey.google is not None:
@ -1663,17 +1668,18 @@ class Story(object):
self.hugvey.google.stop() self.hugvey.google.stop()
def calculateFinishesForMsg(self, msgId, depth = 0, checked = []): def calculateFinishesForMsg(self, msgId, depth = 0, checked = []):
# if msgId in checked: if msgId in checked:
# return [] return []
#
# checked.append(msgId) checked.append(msgId)
if not msgId in self.directionsPerMsg or len(self.directionsPerMsg[msgId]) < 1: if not msgId in self.directionsPerMsg or len(self.directionsPerMsg[msgId]) < 1:
# is finish # is finish
return [msgId] return [msgId]
if depth > 100: if depth == 500:
return [] self.logger.warn(f"Very deep hidden message to calculate finish for: msgId {msgId}")
# return []
finishes = [] finishes = []
for d in self.directionsPerMsg[msgId]: for d in self.directionsPerMsg[msgId]:
@ -1743,7 +1749,7 @@ class Story(object):
def storeState(self): def storeState(self):
# TODO: stop stopwatch # TODO: stop stopwatch
fn = self.getStateFilename(self.hugvey.id) fn = self.getStateFilename(self.hugvey.lightId)
tmpfn = fn + '.tmp' tmpfn = fn + '.tmp'
self.stateSave = time.time() self.stateSave = time.time()
with open(tmpfn, 'wb') as fp: with open(tmpfn, 'wb') as fp:
@ -1756,7 +1762,7 @@ class Story(object):
self.logger.debug(f"saved state to {fn}") self.logger.debug(f"saved state to {fn}")
def hasSavedState(self): def hasSavedState(self):
return self.hugveyHasSavedState(self.hugvey.id) return self.hugveyHasSavedState(self.hugvey.lightId)
@classmethod @classmethod
def hugveyHasSavedState(cls, hv_id): def hugveyHasSavedState(cls, hv_id):
@ -1765,7 +1771,7 @@ class Story(object):
@classmethod @classmethod
def loadStoryFromState(cls, hugvey_state): def loadStoryFromState(cls, hugvey_state):
# restart stopwatch # restart stopwatch
with open(cls.getStateFilename(hugvey_state.id), 'rb') as fp: with open(cls.getStateFilename(hugvey_state.lightId), 'rb') as fp:
story = pickle.load(fp) story = pickle.load(fp)
story.hugvey = hugvey_state story.hugvey = hugvey_state

View file

@ -992,6 +992,17 @@ class Graph {
"uploaded" "uploaded"
) : 'Auto-generated') ) : 'Auto-generated')
); );
let lightOptionNone = {'value': null}
let lightOptionOn = {'value': 1}
let lightOptionOff = {'value': 0}
if(msg.hasOwnProperty('light')) {
if(msg['light'] === 1) lightOptionOn['selected'] = 'selected';
if(msg['light'] === 0) lightOptionOff['selected'] = 'selected';
if(msg['light'] === null) lightOptionNone['selected'] = 'selected';
}
let msgInfoEl = crel( 'div', { 'class': 'msg__info' }, let msgInfoEl = crel( 'div', { 'class': 'msg__info' },
crel('div', { crel('div', {
'class':'btn btn--delete btn--delete-msg', 'class':'btn btn--delete btn--delete-msg',
@ -1125,6 +1136,24 @@ class Graph {
'change': this.getEditEventListener() 'change': this.getEditEventListener()
} }
} ) } )
),
crel( 'label',
crel( 'span', {
"title": "What to do with the light when this message is triggered?"
}, 'Light change' ),
crel( 'select', {
'name': msg['@id'] + '-light',
'on': {
'change': function(e) {
msg['light'] = e.target.value === "null" ? null : parseInt(e.target.value);
panopticon.graph.build();
}
}
},
crel('option', lightOptionNone, "Do nothing"),
crel('option', lightOptionOn, "Turn on"),
crel('option', lightOptionOff, "Turn off")
)
) )
); );
msgEl.appendChild( msgInfoEl ); msgEl.appendChild( msgInfoEl );
@ -1550,6 +1579,7 @@ class Graph {
"text": "New", "text": "New",
"start": false, "start": false,
"afterrunTime": 0.5, "afterrunTime": 0.5,
"light": null,
} }
this.data.push( msg ); this.data.push( msg );
@ -1717,7 +1747,7 @@ class Graph {
...this.directions, ...this.diversions] ...this.directions, ...this.diversions]
let d = []; let d = [];
// let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'x', 'y', 'vx', 'vy'] // let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'x', 'y', 'vx', 'vy']
let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'vx', 'vy'] let toRemove = ['sourceX', 'sourceY', 'targetX', 'targetY', 'x', 'y', 'vx', 'vy']
for ( let node of this.data ) { for ( let node of this.data ) {
let n = {}; let n = {};
// console.log( node['source'] ); // console.log( node['source'] );