Source code for sensors.main

"""
This file gets executed when a new client side session is created. The functions of :file:`app_hook.py` 
will already have returned the corresponding objects and variables that are needed to run this script.
"""

# os methods for manipulating paths
import os
# json, OrderedDict to get data format for Import/Export database
import json
from collections import OrderedDict
# Bokeh basics 
from bokeh.io import curdoc
from bokeh.models.widgets import Tabs
from bokeh.models import Button, Div
from bokeh.layouts import column, row

# import class for audio data handling
from sensors.Utilities.pyaudiohandler import PyAudioHandler
from sensors.Utilities.write_meta_data import WriteMetaData

# import tab classes
from sensors.GUIclasses.info import InfoTab
from sensors.GUIclasses.picam_stream import CamStreamTab
from sensors.GUIclasses.audio_stream import AudioStreamTab
from sensors.GUIclasses.triggered_save import TriggeredSaveTab
from sensors.GUIclasses.single_save import SingleSaveTab
from sensors.GUIclasses.data_viewer import DataViewerTab
from sensors.GUIclasses.export import ExportTab

import RPi.GPIO as GPIO

from concurrent.futures import ThreadPoolExecutor


[docs]def panelActive(attr, old, new): """Function gets called on tab change. It deactivates the ringbuffer update if its tab is not active to save resources. Analogous behaviour for triggered respectively single save tab. """ # only execute if audio device found, stops ringbuffer stream if corresponding tab is not active if config.audio_devices[1] is not None: if all_tabs.active == 0: if visual_ringbuffer.btn_wingbeats.label == 'Stop Stream': visual_ringbuffer.do_update() elif all_tabs.active == 1: if visual_ringbuffer.btn_wingbeats.label == 'Stop Stream': visual_ringbuffer.do_update() elif all_tabs.active == 2: if visual_ringbuffer.btn_wingbeats.label == 'Stop Stream': visual_ringbuffer.do_update() elif all_tabs.active == 3: # if visual_trigger.btn_wingbeats.label == 'Stop Stream': # visual_trigger.do_update() pass else: if visual_ringbuffer.btn_wingbeats.label == 'Stop Stream': visual_ringbuffer.do_update()
# if visual_trigger.btn_wingbeats.label == 'Stop Stream': # visual_trigger.do_update()
[docs]def add_viewer_tab(): """Function gets called on button click. It adds an extra ViewerTab and updates the Bokeh visualization. """ curdoc().session_context.request.viewer_counter += 1 all_tabs.tabs.append(DataViewerTab(config).tab) all_tabs.update(tabs=all_tabs.tabs)
[docs]def shutdown_server(): """Function gets called on button click. Shuts down Bokeh server. """ print('Shutting down Bokeh server!') GPIO.setmode(GPIO.BCM) GPIO.setup(config.GPIO_Switch, GPIO.OUT) GPIO.output(config.GPIO_Switch, GPIO.LOW) exit(0)
# the following lines of code get executed if a bokeh server is instantiated, # but will be ignored if Sphinx is creating an auto documentation, "docs" for local and "source" for RTD html creation if os.path.basename(os.path.normpath(os.path.abspath('.'))) == 'docs' or \ os.path.basename(os.path.normpath(os.path.abspath('.'))) == 'source': print('Sphinx automatic api documentation running!') else: # get config from on_session_load in app hooks config = curdoc().session_context.server_context.config # initialize ThreadPoolExecutor and pass to config executor = ThreadPoolExecutor(max_workers=10) config.executor = executor # add curdoc to config to pass to tab objects config.curdoc = curdoc() # initialize data structure JSON file and add to config and pass to tab objects if os.path.exists('sensors/templates/data_template.json'): with open('sensors/templates/data_template.json', encoding='UTF-8') as f: data_template_dict = json.load(f, object_pairs_hook=OrderedDict) f.close() data_template_dict["sensor_id"] = config.sensor_id data_template_dict["user_id"] = config.user_id data_template_dict["sensor_location"]["postcode"] = config.postcode data_template_dict["sensor_location"]["name"] = config.name data_template_dict["sensor_location"]["latitude"] = config.latitude data_template_dict["sensor_location"]["longitude"] = config.longitude data_template_dict["sensor_location"]["gps_masked"] = config.gps_masked print('Loaded data format!') else: print('No data format template file found!\nShutting down Bokeh server!') exit(0) config.data = data_template_dict # initialize species JSON file and add to config and pass to tab objects if os.path.exists('sensors/templates/species_template.json'): with open('sensors/templates/species_template.json', encoding='UTF-8') as f: species_template_dict = json.load(f, object_pairs_hook=OrderedDict) f.close() print('Loaded species list!') else: print('No data format template file found!\nShutting down Bokeh server!') exit(0) config.species = species_template_dict # initialize tab list tabs_list = list() # add info tab tabs_list.append(InfoTab(config).tab) # include control tabs if it's the only active session (app_hooks.py) and corresponding devices are connected # reload is not working atm, because always 1 active session existent (destruction of old session happening # after creation of new one) if curdoc().session_context.request.master_session: if config.camera is not None: visual_camera = CamStreamTab(config) config.visual_camera = visual_camera tabs_list.append(visual_camera.tab) if config.audio_devices[1] is not None: if config.wb_triggered_save: visual_trigger = TriggeredSaveTab(config) else: visual_trigger = SingleSaveTab(config) tabs_list.append(visual_trigger.tab) visual_ringbuffer = AudioStreamTab(config) # tabs_list.append(visual_ringbuffer.tab) # initialize audio thread, save audio object to session_context to kill thread after session destroyed audio = PyAudioHandler(visual_trigger, visual_ringbuffer) audio.start() curdoc().session_context.audio = audio # add export tab tabs_list.append(ExportTab(config).tab) # add viewer tab tabs_list.append(DataViewerTab(config).tab) # create tab object from tab list, only check for active tabs in master session all_tabs = Tabs(tabs=tabs_list) if curdoc().session_context.request.master_session: all_tabs.on_change('active', panelActive) # create exit button btn_exit = Button(label='Shutdown server', button_type="danger", width=115) btn_exit.on_click(shutdown_server) # create extra ViewerTab at button click btn_add_tab = Button(label='Add Data Viewer', button_type='primary', width=115) btn_add_tab.on_click(add_viewer_tab) # add osi logo and final layout of all elements in current document logo_osi = """<div><img src="sensors/static/logos/osi.svg" width="32"></div>""" logo_kinsecta = """<div><img src="sensors/static/logos/kinsecta.svg" width="32" ></div>""" curdoc().add_root(column(row(Div(text=logo_kinsecta), Div(text=logo_osi), btn_exit, btn_add_tab), all_tabs)) # browser tab name curdoc().title = 'KInsecta Multisensors - Bokeh'