From ed67317ce86e6e08c5cfae64f579d412a5f0609e Mon Sep 17 00:00:00 2001 From: Stan Date: Mon, 6 Mar 2017 13:24:05 +0100 Subject: [PATCH 01/60] Hardware update, user sockets --- readme.md | 4 +- src/opsoro/__init__.py | 3 +- src/opsoro/apps/app_template/__init__.py | 10 +- src/opsoro/apps/circumplex/__init__.py | 12 +- src/opsoro/apps/cockpit/__init__.py | 11 +- src/opsoro/apps/configurator/__init__.py | 9 +- src/opsoro/apps/lua_scripting/__init__.py | 13 +- src/opsoro/apps/lua_scripting/scripthost.py | 10 +- .../static/ono-lua-highlighter.js | 16 +- .../templates/lua_scripting.html | 6 +- src/opsoro/apps/preferences/__init__.py | 11 +- .../preferences/templates/preferences.html | 6 +- src/opsoro/apps/sliders/__init__.py | 9 +- .../apps/sliders/templates/sliders.html | 6 +- src/opsoro/apps/social_response/__init__.py | 259 ++++++++ .../apps/social_response/static/app.css | 0 src/opsoro/apps/social_response/static/app.js | 3 + .../templates/social_response.html | 45 ++ src/opsoro/apps/social_script/__init__.py | 9 +- src/opsoro/apps/social_script/static/app.js | 4 +- src/opsoro/apps/sounds/__init__.py | 10 +- src/opsoro/apps/sounds/static/app.js | 1 + src/opsoro/apps/sounds/templates/sounds.html | 4 +- src/opsoro/apps/touch_graph/__init__.py | 14 +- .../touch_graph/templates/touch_graph.html | 4 +- .../apps/visual_programming/__init__.py | 11 +- .../apps/visual_programming/static/app.js | 12 +- .../static/custom_blocks/hardware.js | 2 +- .../static/custom_blocks/neopixel.js | 12 +- .../static/custom_blocks/servo.js | 8 +- .../static/custom_blocks/touch.js | 4 +- src/opsoro/config/default.conf | 593 +++++++++--------- src/opsoro/config/default_grid.conf | 36 +- src/opsoro/config/default_ono.conf | 426 +++++++++++++ src/opsoro/config/grid_pin.txt | 17 + src/opsoro/config/preferences.yaml | 8 +- src/opsoro/console_msg.py | 16 +- .../lua_scripting/scripts/CanvasPitch.lua | 8 +- .../data/lua_scripting/scripts/EdgeHue.lua | 12 +- .../lua_scripting/scripts/EmotionButton.lua | 12 +- .../data/lua_scripting/scripts/EyeButton.lua | 12 +- .../data/lua_scripting/scripts/HRI2016.lua | 8 +- .../data/lua_scripting/scripts/HRI2016b.lua | 8 +- .../data/lua_scripting/scripts/NeoBlink.lua | 14 +- .../data/lua_scripting/scripts/NeoButtons.lua | 28 +- .../data/lua_scripting/scripts/NeoKeypad.lua | 16 +- .../lua_scripting/scripts/ONA_testing_1_1.lua | 8 +- .../lua_scripting/scripts/introduction.lua | 8 +- .../scripts/old/qsddsqfdssqdf.lua | 4 +- .../data/lua_scripting/scripts/step10.lua | 8 +- .../data/lua_scripting/scripts/step11.lua | 8 +- .../scripts/currentscript.xml.tmp | 2 +- src/opsoro/dof/servo.py | 2 +- src/opsoro/hardware/SPI_commands.txt | 52 ++ src/opsoro/hardware/__init__.py | 483 +------------- src/opsoro/hardware/analog.py | 33 + src/opsoro/hardware/capacitive.py | 115 ++++ src/opsoro/hardware/dummy_spidev.py | 15 + src/opsoro/hardware/i2c.py | 225 ++----- src/opsoro/hardware/neopixel.py | 118 ++++ src/opsoro/hardware/servo.py | 75 +++ src/opsoro/hardware/spi.py | 66 ++ src/opsoro/hardware/test_hardware.py | 358 +++++++++++ src/opsoro/hardware/usb_serial.py | 43 ++ src/opsoro/play.py | 57 ++ src/opsoro/robot.py | 24 +- src/opsoro/server/__init__.py | 136 ++-- .../server/request_handlers/__init__.py | 255 ++++---- .../request_handlers/opsoro_data_requests.py | 11 +- src/opsoro/server/static/js/opsoro.js | 56 +- src/opsoro/server/static/js/robot/virtual.js | 4 +- .../server/static/js/robot_new/virtual.js | 4 +- src/opsoro/server/static/js/virtual_old.js | 4 +- .../server/templates/_body_scripts.html | 1 + src/opsoro/server/templates/login.html | 16 +- src/opsoro/server/templates/page.html | 1 - src/opsoro/stt.py | 29 + 77 files changed, 2589 insertions(+), 1374 deletions(-) create mode 100644 src/opsoro/apps/social_response/__init__.py create mode 100644 src/opsoro/apps/social_response/static/app.css create mode 100644 src/opsoro/apps/social_response/static/app.js create mode 100644 src/opsoro/apps/social_response/templates/social_response.html create mode 100644 src/opsoro/config/default_ono.conf create mode 100644 src/opsoro/config/grid_pin.txt create mode 100644 src/opsoro/hardware/SPI_commands.txt create mode 100644 src/opsoro/hardware/analog.py create mode 100644 src/opsoro/hardware/capacitive.py create mode 100644 src/opsoro/hardware/dummy_spidev.py create mode 100644 src/opsoro/hardware/neopixel.py create mode 100644 src/opsoro/hardware/servo.py create mode 100644 src/opsoro/hardware/spi.py create mode 100644 src/opsoro/hardware/test_hardware.py create mode 100644 src/opsoro/hardware/usb_serial.py create mode 100644 src/opsoro/play.py create mode 100644 src/opsoro/stt.py diff --git a/readme.md b/readme.md index d944926..d29e940 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ OnoSW is the software framework for [OPSORO](http://www.opsoro.be/), to be used 5. Install Python development files, Avahi daemon, LuaJIT ``` - sudo apt-get install python2.7-dev avahi-daemon libluajit-5.1-dev + sudo apt-get install python2.7-dev avahi-daemon libluajit-5.1-dev git ``` 6. Install PIP @@ -41,7 +41,7 @@ OnoSW is the software framework for [OPSORO](http://www.opsoro.be/), to be used 8. Install Python packages (flask, flask-login, pyyaml, pluginbase, sockjs-tornado, simplejson, lupa, numpy, scipy, spidev) ``` - sudo pip install flask flask-login pyyaml pluginbase sockjs-tornado simplejson lupa numpy spidev + sudo pip install flask flask-login pyyaml pluginbase sockjs-tornado simplejson lupa numpy spidev gitpython flask-babel noise gitpython pyserial sudo apt-get install -y python-smbus i2c-tools sudo apt-get install -y python-scipy ``` diff --git a/src/opsoro/__init__.py b/src/opsoro/__init__.py index 9ebc8b8..79d84ef 100644 --- a/src/opsoro/__init__.py +++ b/src/opsoro/__init__.py @@ -33,8 +33,7 @@ def sigterm_handler(_signo, _stack_frame): tornado.log.enable_pretty_logging() logger = logging.getLogger() logger.setLevel(LOG_LEVEL) - handler = logging.handlers.TimedRotatingFileHandler( - LOG_FILENAME, when="midnight", backupCount=3) + handler = logging.handlers.TimedRotatingFileHandler(LOG_FILENAME, when="midnight", backupCount=3) formatter = logging.Formatter("%(asctime)s %(levelname)-8s %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) diff --git a/src/opsoro/apps/app_template/__init__.py b/src/opsoro/apps/app_template/__init__.py index 474ad5f..8f7040d 100644 --- a/src/opsoro/apps/app_template/__init__.py +++ b/src/opsoro/apps/app_template/__init__.py @@ -19,16 +19,10 @@ 'icon': 'fa-info', 'color': '#15e678', 'allowed_background': False, - 'robot_state': 0} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - - def setup_pages(opsoroapp): app_bp = Blueprint( config['formatted_name'], diff --git a/src/opsoro/apps/circumplex/__init__.py b/src/opsoro/apps/circumplex/__init__.py index 07c5715..26c54ad 100644 --- a/src/opsoro/apps/circumplex/__init__.py +++ b/src/opsoro/apps/circumplex/__init__.py @@ -1,19 +1,15 @@ from flask import Blueprint, render_template +from opsoro.robot import Robot + config = {'full_name': 'Circumplex', 'icon': 'fa-meh-o', 'color': '#15e678', 'allowed_background': False, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - - def setup_pages(opsoroapp): circumplex_bp = Blueprint( config['formatted_name'], diff --git a/src/opsoro/apps/cockpit/__init__.py b/src/opsoro/apps/cockpit/__init__.py index b2b112f..63ca179 100644 --- a/src/opsoro/apps/cockpit/__init__.py +++ b/src/opsoro/apps/cockpit/__init__.py @@ -12,15 +12,10 @@ 'icon': 'fa-rocket', 'color': '#ff517e', 'allowed_background': False, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - clientconn = None # dof_positions = {} @@ -87,7 +82,7 @@ def s_setservopos(conn, data): value = constrain(value, 500, 2500) with Hardware.lock: - Hardware.servo_set(pin_number, value) + Hardware.Servo.set(pin_number, value) opsoroapp.register_app_blueprint(app_bp) diff --git a/src/opsoro/apps/configurator/__init__.py b/src/opsoro/apps/configurator/__init__.py index 51b6e53..42a1ee9 100644 --- a/src/opsoro/apps/configurator/__init__.py +++ b/src/opsoro/apps/configurator/__init__.py @@ -28,15 +28,10 @@ 'icon': 'fa-pencil', 'color': '#ff517e', 'allowed_background': False, - 'robot_state': 0} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.MANUAL} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) diff --git a/src/opsoro/apps/lua_scripting/__init__.py b/src/opsoro/apps/lua_scripting/__init__.py index 6706327..33097ec 100644 --- a/src/opsoro/apps/lua_scripting/__init__.py +++ b/src/opsoro/apps/lua_scripting/__init__.py @@ -4,22 +4,19 @@ import os import glob import time -import lupa +# import lupa from .scripthost import ScriptHost +from opsoro.robot import Robot + config = {'full_name': 'Lua Scripting', 'icon': 'fa-terminal', 'color': '#36c9ff', 'allowed_background': True, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - clientconn = None sh = None script = '' diff --git a/src/opsoro/apps/lua_scripting/scripthost.py b/src/opsoro/apps/lua_scripting/scripthost.py index 75d4e65..697114a 100644 --- a/src/opsoro/apps/lua_scripting/scripthost.py +++ b/src/opsoro/apps/lua_scripting/scripthost.py @@ -355,23 +355,23 @@ def ignore_one(ign, *args, **kwargs): return attr def cap_get_filtered_data(self): - return self.runtime.table_from(Hardware.cap_get_filtered_data()) + return self.runtime.table_from(Hardware.Capacitive.get_filtered_data()) def cap_get_baseline_data(self): - return self.runtime.table_from(Hardware.cap_get_baseline_data()) + return self.runtime.table_from(Hardware.Capacitive.get_baseline_data()) def ana_read_all_channels(self): - return self.runtime.table_from(Hardware.cap_get_baseline_data()) + return self.runtime.table_from(Hardware.Capacitive.get_baseline_data()) def spi_command(self, cmd, params=None, returned=0, delay=0): if params is not None: params = list(params.values()) return self.runtime.table_from( - Hardware.spi_command(cmd, params, returned, delay)) + Hardware.SPI.command(cmd, params, returned, delay)) def servo_set_all(self, pos_list): pos_list = list(pos_list.values()) - Hardware.servo_set_all(post_list) + Hardware.Servo.set_all(post_list) class LuaAnimate(object): diff --git a/src/opsoro/apps/lua_scripting/static/ono-lua-highlighter.js b/src/opsoro/apps/lua_scripting/static/ono-lua-highlighter.js index ce4faf0..c6f7576 100644 --- a/src/opsoro/apps/lua_scripting/static/ono-lua-highlighter.js +++ b/src/opsoro/apps/lua_scripting/static/ono-lua-highlighter.js @@ -13,14 +13,14 @@ var OnoLuaHighlightRules = function() { "init|add_button|add_key|is_button_pressed|is_key_pressed|"+ // Hardware class methods - "ping|reset|led_on|led_off|i2c_detect|i2c_read8|i2c_write8|i2c_read16|"+ - "i2C_write16|servo_init|servo_enable|servo_disable|servo_neutral|"+ - "servo_set|servo_set_all|cap_init|cap_set_threshold|"+ - "cap_get_filtered_data|cap_get_baseline_data|cap_get_touched|"+ - "cap_set_gpio_pinmode|cap_read_gpio|cap_write_gpio|neo_init|neo_enable|"+ - "neo_disable|neo_set_brightness|neo_show|neo_set_pixel|neo_set_range|"+ - "neo_set_all|neo_set_pixel_hsv|neo_set_range_hsv|neo_set_all_hsv|"+ - "ana_read_channel|ana_read_all_channels|"+ + "ping|reset|led_on|led_off|I2C:detect|I2C:read8|I2C:write8|I2C:read16|"+ + "I2C:write16|Servo:init|Servo:enable|Servo:disable|Servo:neutral|"+ + "Servo:set|Servo:set_all|Capacitive:init|Capacitive:set_threshold|"+ + "Capacitive:get_filtered_data|Capacitive:get_baseline_data|Capacitive:get_touched|"+ + "Capacitive:set_gpio_pinmode|Capacitive:read_gpio|Capacitive:write_gpio|Neopixel:init|Neopixel:enable|"+ + "Neopixel:disable|Neopixel:set_brightness|Neopixel:show|Neopixel:set_pixel|Neopixel:set_range|"+ + "Neopixel:set_all|Neopixel:set_pixel_hsv|Neopixel:set_range_hsv|Neopixel:set_all_hsv|"+ + "Analog:read_channel|Analog:read_all_channels|"+ // Sound class methods "say_tts|play_file|"+ diff --git a/src/opsoro/apps/lua_scripting/templates/lua_scripting.html b/src/opsoro/apps/lua_scripting/templates/lua_scripting.html index ddf51de..7cef973 100644 --- a/src/opsoro/apps/lua_scripting/templates/lua_scripting.html +++ b/src/opsoro/apps/lua_scripting/templates/lua_scripting.html @@ -1,6 +1,6 @@ {% extends "app_base.html" %} -{% block head %} +{% block app_head %} {% endblock %} @@ -147,11 +147,11 @@ // Setup websocket connection. var conn = null; var connReady = false; - conn = new SockJS("http://" + window.location.host + "/sockjs"); + conn = new SockJS("http://" + window.location.host + "/appsockjs"); conn.onopen = function () { console.log("SockJS connected."); - $.ajax({url: "/sockjstoken", cache: false}).done(function (data) { + $.ajax({url: "/appsockjstoken", cache: false}).done(function (data) { conn.send(JSON.stringify({action: "authenticate", token: data})); connReady = true; console.log("SockJS authenticated."); diff --git a/src/opsoro/apps/preferences/__init__.py b/src/opsoro/apps/preferences/__init__.py index 0a7a192..5ae5462 100644 --- a/src/opsoro/apps/preferences/__init__.py +++ b/src/opsoro/apps/preferences/__init__.py @@ -1,7 +1,7 @@ from __future__ import with_statement from opsoro.console_msg import * -# from opsoro.robot import Robot +from opsoro.robot import Robot # from opsoro.hardware import Hardware from opsoro.preferences import Preferences @@ -13,15 +13,10 @@ 'icon': 'fa-cog', 'color': '#555', 'allowed_background': False, - 'robot_state': 0} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.MANUAL} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - # clientconn = None # dof_positions = {} diff --git a/src/opsoro/apps/preferences/templates/preferences.html b/src/opsoro/apps/preferences/templates/preferences.html index 707a970..92999b6 100644 --- a/src/opsoro/apps/preferences/templates/preferences.html +++ b/src/opsoro/apps/preferences/templates/preferences.html @@ -1,5 +1,5 @@ {% extends "app_base.html" %} -{% block head %}{% endblock %} +{% block app_head %}{% endblock %} {% block app_content %}
@@ -62,10 +62,10 @@
- Update available! + Update available!
- Up-to-date! + Up-to-date!
diff --git a/src/opsoro/apps/sliders/__init__.py b/src/opsoro/apps/sliders/__init__.py index 4e80fcc..f240450 100644 --- a/src/opsoro/apps/sliders/__init__.py +++ b/src/opsoro/apps/sliders/__init__.py @@ -13,15 +13,10 @@ 'icon': 'fa-sliders', 'color': '#15e678', 'allowed_background': False, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - clientconn = None # dof_positions = {} diff --git a/src/opsoro/apps/sliders/templates/sliders.html b/src/opsoro/apps/sliders/templates/sliders.html index c16b1dd..3cb23e2 100644 --- a/src/opsoro/apps/sliders/templates/sliders.html +++ b/src/opsoro/apps/sliders/templates/sliders.html @@ -1,6 +1,6 @@ {% extends "app_base.html" %} -{% block head %} +{% block app_head %} {% endblock %} @@ -98,12 +98,12 @@ // Setup websocket connection. var conn = null; var connReady = false; - conn = new SockJS("http://" + window.location.host + "/sockjs"); + conn = new SockJS("http://" + window.location.host + "/appsockjs"); conn.onopen = function(){ console.log("SockJS connected."); $.ajax({ - url: "/sockjstoken", + url: "/appsockjstoken", cache: false }) .done(function(data) { diff --git a/src/opsoro/apps/social_response/__init__.py b/src/opsoro/apps/social_response/__init__.py new file mode 100644 index 0000000..d5b99a7 --- /dev/null +++ b/src/opsoro/apps/social_response/__init__.py @@ -0,0 +1,259 @@ +from __future__ import with_statement + +from flask import Blueprint, render_template, request, redirect, url_for, flash, send_from_directory + +from opsoro.console_msg import * +from opsoro.hardware import Hardware +from opsoro.robot import Robot +from opsoro.expression import Expression +from opsoro.stoppable_thread import StoppableThread +from opsoro.sound import Sound + + +from functools import partial +import os +import time +from random import randint + +constrain = lambda n, minn, maxn: max(min(maxn, n), minn) +get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) + +config = {'full_name': 'Social Response', + 'icon': 'fa-share-square', + 'color': '#15e678', + 'allowed_background': True, + 'robot_state': 1} + + # 'connection': Robot.Connection.ONLINE, + # 'activation': Robot.Activation.AUTO} +config['formatted_name'] = config['full_name'].lower().replace(' ', '_') + + +loop_t = None +# clientconn = None +# running = False + +# ------------------------------------------------------------------------------ +# Facebook stuff --------------------------------------------------------------- +# ------------------------------------------------------------------------------ +import urllib2 +import json + +def get_page_data(page_id,fields,access_token): + api_endpoint = "https://graph.facebook.com/v2.4/" + fb_graph_url = api_endpoint+page_id+'?fields='+fields+'&access_token='+access_token + try: + api_request = urllib2.Request(fb_graph_url) + api_response = urllib2.urlopen(api_request) + + try: + return json.loads(api_response.read()) + except (ValueError, KeyError, TypeError): + return "JSON error" + + except IOError, e: + if hasattr(e, 'code'): + return e.code + elif hasattr(e, 'reason'): + return e.reason + +page_id = 'opsoro' # username or id +field = 'fan_count' +token = 'EAAaBZCzjU8H8BAFV7KudJn0K1V12CDBHqTIxYu6pVh7cpZAbt1WbZCyZBeSZC472fpPd0ZAkWC1tMrfAY26XnQJUR2rNrMQncQ9OGJlie3dUeQVvabZCwNmGaLL4FGHjZBVTajid16FL5niGWytlwZCiFDgj6yjIsZAAAZD' # Access Token + +# ------------------------------------------------------------------------------ +# Twitter stuff ---------------------------------------------------------------- +# ------------------------------------------------------------------------------ +import tweepy +#Variables that contains the user credentials to access Twitter API +access_token = '735437381696905216-BboISY7Qcqd1noMDY61zN75CdGT0OSc' +access_token_secret = 'd3A8D1ttrCxYV76pBOB389YqoLB32LiE0RVyoFwuMKUMb' +consumer_key = 'AcdgqgujzF06JF6zWrfwFeUfF' +consumer_secret = 'ss0wVcBTFAT6nR6hXrqyyOcFOhpa2sNW4cIap9JOoepcch93ky' + +twitterWords = ['@dekrook', '#opsoro'] + +auth = tweepy.OAuthHandler(consumer_key, consumer_secret) +auth.set_access_token(access_token, access_token_secret) + +#override tweepy.StreamListener to add logic to on_status +class MyStreamListener(tweepy.StreamListener): + def on_status(self, status): + print(status.text) + # Go_Crazy(text=status.text, twitter=True) + txt = status.text + for tword in twitterWords: + txt = txt.replace(tword, '') + Go_Crazy(text=txt, twitter=True) + +api = tweepy.API(auth) +myStreamListener = MyStreamListener() +myStream = tweepy.Stream(auth = api.auth, listener=myStreamListener) + +# followers = [] +# likes = 0 +# counter = 0 +sleep_time = 5 + +# ------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ + +# Laughing Happy Sad Angry Surprised Afraid Disgusted Tired +emotions_phis = [36.0, 18.0, 198.0, 153.0, 90.0, 125.0, 172.0, 270.0] +sounds = ['smb_1-up.wav', 'smb_coin.wav', 'smb_powerup.wav', 'Whistle.wav', 'Woohoo.wav', 'Small_Applause.wav'] +sound_int = -1 +emotion_int = -1 +prev_emotion_int = emotion_int +prev_sound_int = sound_int + + + +def Go_Crazy(text='', twitter=False, facebook=False): + print_info('Do something!') + + global prev_emotion_int + global emotion_int + global prev_sound_int + global sound_int + + while sound_int == prev_sound_int: + sound_int = randint(0,len(sounds)-1) + + while emotion_int == prev_emotion_int: + emotion_int = randint(0,len(emotions_phis)-1) + + prev_sound_int = sound_int + prev_emotion_int = emotion_int + + if len(text) > 1: + Sound.say_tts(text) + else: + Sound.play_file(sounds[sound_int]) + Expression.set_emotion_r_phi(1.0, emotions_phis[emotion_int], True, 0.5) + + Hardware.Serial.send('anim\n') + + if twitter: + Hardware.Serial.send('set\nset 000000000000000000247e24247e24\n') + + if facebook: + Hardware.Serial.send('set\nset 00000000000000000818185f5f5f5e5e\n') + + loop_t.sleep(2) + + + print_info('Done doing something!') + +def Loop(): + time.sleep(0.05) # delay + + # global clientconn + + # global counter + counter = 0 + + # Initialize current Likes + # global likes + likes = 0 + try: + likes = int(get_page_data(page_id, field, token)[field]) + except Exception as e: + pass + + # Initialize current followers + # global followers + followers = [] + new_followers = [] + for user in tweepy.Cursor(api.followers, screen_name=page_id).items(): + followers.append(user.name) + + while not loop_t.stopped(): + # if running: + data = {} + + print_info('Checking social...') + + # if clientconn: + # clientconn.send_data('updateelectrodes', + # {'electrodedata': data}) + + try: + # Facebook: + new_likes = int(get_page_data(page_id, field, token)[field]) + if new_likes > likes: + print_info('Facebook: ' + str(new_likes - likes) + ' new likes.') + Go_Crazy(facebook=True) + + likes = new_likes + # print "Likes: "+ str(page_data[field]) + + # Twitter requests: 1/minute + if len(new_followers) > 0: + username = new_followers.pop() + followers.append(username) + Go_Crazy(text='Hello ' + str(username), twitter=True) + + # global counter + counter += 1 + if counter >= (60 / sleep_time): + for user in tweepy.Cursor(api.followers, screen_name=page_id).items(): + if user.name not in followers: + new_followers.append(user.name) + # print 'new follower: ', user.name + if len(new_followers) > 0: + print_info('Twitter: ' + str(len(new_followers)) + ' new followers.') + counter = 0 + + except Exception as e: + print e + print_warning('Social error, internet, limit, ...?') + + + loop_t.sleep(sleep_time) + +def setup_pages(opsoroapp): + app_bp = Blueprint( + config['formatted_name'], + __name__, + template_folder='templates', + static_folder='static') + + @app_bp.route('/', methods=['GET']) + @opsoroapp.app_view + def index(): + data = { + 'actions': {}, + 'data': [], + } + + action = request.args.get('action', None) + if action != None: + data['actions'][action] = request.args.get('param', None) + + return opsoroapp.render_template(config['formatted_name'] + '.html', **data) + + # @app_bp.route('/demo') + # @opsoroapp.app_view + # def demo(): + # data = { + # } + # + # return opsoroapp.render_template('app.html', **data) + + opsoroapp.register_app_blueprint(app_bp) + + +def setup(opsoroapp): + pass + +def start(opsoroapp): + global loop_t + global myStream + myStream.filter(track=twitterWords, async=True) + loop_t = StoppableThread(target=Loop) + +def stop(opsoroapp): + global loop_t + global myStream + myStream.disconnect() + loop_t.stop() diff --git a/src/opsoro/apps/social_response/static/app.css b/src/opsoro/apps/social_response/static/app.css new file mode 100644 index 0000000..e69de29 diff --git a/src/opsoro/apps/social_response/static/app.js b/src/opsoro/apps/social_response/static/app.js new file mode 100644 index 0000000..32029a6 --- /dev/null +++ b/src/opsoro/apps/social_response/static/app.js @@ -0,0 +1,3 @@ +$(document).ready(function() { + +}); diff --git a/src/opsoro/apps/social_response/templates/social_response.html b/src/opsoro/apps/social_response/templates/social_response.html new file mode 100644 index 0000000..29061d7 --- /dev/null +++ b/src/opsoro/apps/social_response/templates/social_response.html @@ -0,0 +1,45 @@ +{% extends "app_base.html" %} +{% block app_head %} + + + +{% endblock %} +{% block app_toolbar %}{% endblock %} + + +{% block sidebar_left %}{% endblock %} +{% block sidebar_right %}{% endblock %} + +{% block app_content %} +
+ + Facebook +
+
+ + Twitter +
+ + + +
+
+ {% if not online %} + + {% endif %} + +{% endblock %} +{% block app_scripts %} + + + + + +{% endblock %} +{% block app_modals %} + +{% endblock %} diff --git a/src/opsoro/apps/social_script/__init__.py b/src/opsoro/apps/social_script/__init__.py index b7af96e..63887ce 100644 --- a/src/opsoro/apps/social_script/__init__.py +++ b/src/opsoro/apps/social_script/__init__.py @@ -7,6 +7,7 @@ import math import cmath +from opsoro.robot import Robot from opsoro.console_msg import * from opsoro.hardware import Hardware from opsoro.stoppable_thread import StoppableThread @@ -31,14 +32,10 @@ 'icon': 'fa-commenting-o', 'color': '#15e678', 'allowed_background': False, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) diff --git a/src/opsoro/apps/social_script/static/app.js b/src/opsoro/apps/social_script/static/app.js index 6a7b083..d762842 100644 --- a/src/opsoro/apps/social_script/static/app.js +++ b/src/opsoro/apps/social_script/static/app.js @@ -332,11 +332,11 @@ $(document).ready(function(){ // Setup websocket connection. self.conn = null; self.connReady = false; - self.conn = new SockJS("http://" + window.location.host + "/sockjs"); + self.conn = new SockJS("http://" + window.location.host + "/appsockjs"); self.conn.onopen = function(){ $.ajax({ - url: "/sockjstoken", + url: "/appsockjstoken", cache: false }) .done(function(data) { diff --git a/src/opsoro/apps/sounds/__init__.py b/src/opsoro/apps/sounds/__init__.py index 5864592..c2e7fb2 100644 --- a/src/opsoro/apps/sounds/__init__.py +++ b/src/opsoro/apps/sounds/__init__.py @@ -5,20 +5,18 @@ import glob from flask import Blueprint, render_template, request, redirect, url_for, flash from werkzeug import secure_filename + from opsoro.sound import Sound +from opsoro.robot import Robot config = {'full_name': 'Sounds', 'icon': 'fa-volume-up', 'color': '#15e678', 'allowed_background': False, - 'robot_state': 0} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.MANUAL} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) diff --git a/src/opsoro/apps/sounds/static/app.js b/src/opsoro/apps/sounds/static/app.js index d49f367..c2c6126 100644 --- a/src/opsoro/apps/sounds/static/app.js +++ b/src/opsoro/apps/sounds/static/app.js @@ -46,6 +46,7 @@ $(document).ready(function(){ // } // } // }); + return false; }); $("#formTTS").submit(function(e){ diff --git a/src/opsoro/apps/sounds/templates/sounds.html b/src/opsoro/apps/sounds/templates/sounds.html index a4d9b7a..80816e2 100644 --- a/src/opsoro/apps/sounds/templates/sounds.html +++ b/src/opsoro/apps/sounds/templates/sounds.html @@ -1,6 +1,6 @@ {% extends "app_base.html" %} -{% block head %} +{% block app_head %} @@ -101,7 +101,7 @@ {% for soundfile in soundfiles %} - + {{ soundfile }}
{% endfor %} diff --git a/src/opsoro/apps/touch_graph/__init__.py b/src/opsoro/apps/touch_graph/__init__.py index ca61c14..47816aa 100644 --- a/src/opsoro/apps/touch_graph/__init__.py +++ b/src/opsoro/apps/touch_graph/__init__.py @@ -5,6 +5,8 @@ import random import time from flask import Blueprint, render_template, request, redirect, url_for, flash + +from opsoro.robot import Robot from opsoro.stoppable_thread import StoppableThread from opsoro.hardware import Hardware @@ -12,14 +14,10 @@ 'icon': 'fa-hand-o-down', 'color': '#ffaf19', 'allowed_background': False, - 'robot_state': 0} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.MANUAL} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature touch_t = None clientconn = None @@ -38,7 +36,7 @@ def TouchLoop(): data = {} with Hardware.lock: - ret = Hardware.cap_get_filtered_data() + ret = Hardware.Capacitive.get_filtered_data() for i in range(numelectrodes): data[i] = ret[i] @@ -54,7 +52,7 @@ def startcap(electrodes): global running global numelectrodes - Hardware.cap_init(electrodes=electrodes, gpios=0, autoconfig=True) + Hardware.Capacitive.init(electrodes=electrodes, gpios=0, autoconfig=True) numelectrodes = electrodes running = True diff --git a/src/opsoro/apps/touch_graph/templates/touch_graph.html b/src/opsoro/apps/touch_graph/templates/touch_graph.html index 510f83d..31b6d59 100644 --- a/src/opsoro/apps/touch_graph/templates/touch_graph.html +++ b/src/opsoro/apps/touch_graph/templates/touch_graph.html @@ -124,12 +124,12 @@ var conn = null; var connReady = false; - conn = new SockJS("http://" + window.location.host + "/sockjs"); + conn = new SockJS("http://" + window.location.host + "/appsockjs"); conn.onopen = function(){ console.log("SockJS connected."); $.ajax({ - url: "/sockjstoken", + url: "/appsockjstoken", cache: false }) .done(function(data) { diff --git a/src/opsoro/apps/visual_programming/__init__.py b/src/opsoro/apps/visual_programming/__init__.py index 856e2bb..db11b70 100644 --- a/src/opsoro/apps/visual_programming/__init__.py +++ b/src/opsoro/apps/visual_programming/__init__.py @@ -7,19 +7,16 @@ from werkzeug import secure_filename from ..lua_scripting.scripthost import ScriptHost +from opsoro.robot import Robot + config = {'full_name': 'Visual Programming', 'icon': 'fa-puzzle-piece', 'color': '#6e00ff', 'allowed_background': True, - 'robot_state': 1} + 'connection': Robot.Connection.OFFLINE, + 'activation': Robot.Activation.AUTO} config['formatted_name'] = config['full_name'].lower().replace(' ', '_') -# robot_state: -# 0: Manual start/stop -# 1: Start robot automatically (alive feature according to preferences) -# 2: Start robot automatically and enable alive feature -# 3: Start robot automatically and disable alive feature - get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) clientconn = None diff --git a/src/opsoro/apps/visual_programming/static/app.js b/src/opsoro/apps/visual_programming/static/app.js index c0d28ab..f1cb6b6 100644 --- a/src/opsoro/apps/visual_programming/static/app.js +++ b/src/opsoro/apps/visual_programming/static/app.js @@ -125,12 +125,12 @@ $(document).ready(function() { // Setup websocket connection. var conn = null; var connReady = false; - conn = new SockJS("http://" + window.location.host + "/sockjs"); + conn = new SockJS("http://" + window.location.host + "/appsockjs"); conn.onopen = function() { console.log("SockJS connected."); $.ajax({ - url: "/sockjstoken", + url: "/appsockjstoken", cache: false }).done(function(data) { conn.send(JSON.stringify({ @@ -391,9 +391,7 @@ $(document).ready(function() { return; } - var keycode = (event.keyCode ? - event.keyCode : - event.which); + var keycode = (evt.keyCode ? evt.keyCode : evt.which); if (keysDown[keycode] == null) { // First press @@ -415,9 +413,7 @@ $(document).ready(function() { if (!monitorKeypresses) { return; } - var keycode = (event.keyCode ? - event.keyCode : - event.which); + var keycode = (evt.keyCode ? evt.keyCode : evt.which); keysDown[keycode] = null; var elem = $("#ScriptUIKeys .keyboardKey[data-keycode=" + keycode + "]"); diff --git a/src/opsoro/apps/visual_programming/static/custom_blocks/hardware.js b/src/opsoro/apps/visual_programming/static/custom_blocks/hardware.js index 1a80ac7..849866f 100644 --- a/src/opsoro/apps/visual_programming/static/custom_blocks/hardware.js +++ b/src/opsoro/apps/visual_programming/static/custom_blocks/hardware.js @@ -36,6 +36,6 @@ Blockly.Blocks['hardware_readanalog'] = { }; Blockly.Lua['hardware_readanalog'] = function(block) { var dropdown_channel = block.getFieldValue('CHANNEL'); - var code = 'Hardware:ana_read_channel(' + dropdown_channel + ')'; + var code = 'Hardware.Analog:read_channel(' + dropdown_channel + ')'; return [code, Blockly.Lua.ORDER_FUNCTION_CALL]; }; diff --git a/src/opsoro/apps/visual_programming/static/custom_blocks/neopixel.js b/src/opsoro/apps/visual_programming/static/custom_blocks/neopixel.js index 9d3eae2..e383f68 100644 --- a/src/opsoro/apps/visual_programming/static/custom_blocks/neopixel.js +++ b/src/opsoro/apps/visual_programming/static/custom_blocks/neopixel.js @@ -13,7 +13,7 @@ Blockly.Blocks['neo_init'] = { }; Blockly.Lua['neo_init'] = function(block) { var text_numpixels = block.getFieldValue('NUMPIXELS'); - var code = 'Hardware:neo_init(' + text_numpixels + ')\n'; + var code = 'Hardware.Neopixel:init(' + text_numpixels + ')\n'; return code; }; @@ -31,7 +31,7 @@ Blockly.Blocks['neo_brightness'] = { }; Blockly.Lua['neo_brightness'] = function(block) { var value_brightness = Blockly.Lua.valueToCode(block, 'BRIGHTNESS', Blockly.Lua.ORDER_ATOMIC); - var code = 'Hardware:neo_set_brightness(' + value_brightness + ')\n'; + var code = 'Hardware.Neopixel:set_brightness(' + value_brightness + ')\n'; return code; }; @@ -47,7 +47,7 @@ Blockly.Blocks['neo_update'] = { } }; Blockly.Lua['neo_update'] = function(block) { - var code = 'Hardware:neo_show()\n'; + var code = 'Hardware.Neopixel:show()\n'; return code; }; @@ -75,7 +75,7 @@ Blockly.Lua['neo_setpixel'] = function(block) { var g = (hex & 0x00ff00) >> 8; var b = hex & 0x0000ff; - var code = 'Hardware:neo_set_pixel(' + value_pixel + ', ' + r + ', ' + g + ', ' + b + ')\n'; + var code = 'Hardware.Neopixel:set_pixel(' + value_pixel + ', ' + r + ', ' + g + ', ' + b + ')\n'; return code; }; @@ -107,7 +107,7 @@ Blockly.Lua['neo_setrange'] = function(block) { var g = (hex & 0x00ff00) >> 8; var b = hex & 0x0000ff; - var code = 'Hardware:neo_set_range(' + value_start + ', ' + value_end + ', ' + r + ', ' + g + ', ' + b + ')\n'; + var code = 'Hardware.Neopixel:set_range(' + value_start + ', ' + value_end + ', ' + r + ', ' + g + ', ' + b + ')\n'; return code; }; @@ -131,6 +131,6 @@ Blockly.Lua['neo_setall'] = function(block) { var g = (hex & 0x00ff00) >> 8; var b = hex & 0x0000ff; - var code = 'Hardware:neo_set_all(' + r + ', ' + g + ', ' + b + ')\n'; + var code = 'Hardware.Neopixel:set_all(' + r + ', ' + g + ', ' + b + ')\n'; return code; }; diff --git a/src/opsoro/apps/visual_programming/static/custom_blocks/servo.js b/src/opsoro/apps/visual_programming/static/custom_blocks/servo.js index 38c8100..0f4328b 100644 --- a/src/opsoro/apps/visual_programming/static/custom_blocks/servo.js +++ b/src/opsoro/apps/visual_programming/static/custom_blocks/servo.js @@ -10,7 +10,7 @@ Blockly.Blocks['servo_init'] = { } }; Blockly.Lua['servo_init'] = function(block) { - var code = 'Hardware:servo_init()\n'; + var code = 'Hardware.Servo:init()\n'; return code; }; @@ -30,9 +30,9 @@ Blockly.Lua['servo_enabledisable'] = function(block) { var dropdown_onoff = block.getFieldValue('ONOFF'); var code = ''; if(dropdown_onoff == "ON"){ - code = "Hardware:servo_enable()\n" + code = "Hardware.Servo:enable()\n" }else{ - code = "Hardware:servo_disable()\n" + code = "Hardware.Servo:disable()\n" } return code; }; @@ -62,6 +62,6 @@ Blockly.Blocks['servo_set'] = { Blockly.Lua['servo_set'] = function(block) { var dropdown_channel = block.getFieldValue('CHANNEL'); var value_pos = Blockly.Lua.valueToCode(block, 'POS', Blockly.Lua.ORDER_ATOMIC); - var code = 'Hardware:servo_set(' + dropdown_channel + ', ' + value_pos + ')\n'; + var code = 'Hardware.Servo:set(' + dropdown_channel + ', ' + value_pos + ')\n'; return code; }; diff --git a/src/opsoro/apps/visual_programming/static/custom_blocks/touch.js b/src/opsoro/apps/visual_programming/static/custom_blocks/touch.js index baa0cc6..bc6bf62 100644 --- a/src/opsoro/apps/visual_programming/static/custom_blocks/touch.js +++ b/src/opsoro/apps/visual_programming/static/custom_blocks/touch.js @@ -13,7 +13,7 @@ Blockly.Blocks['touch_init'] = { }; Blockly.Lua['touch_init'] = function(block) { var dropdown_electrode = block.getFieldValue('ELECTRODE'); - var code = 'Hardware:cap_init(' + dropdown_electrode + ')\n'; + var code = 'Hardware.Capacitive:init(' + dropdown_electrode + ')\n'; return code; }; @@ -41,7 +41,7 @@ Blockly.Lua['touch_etouched'] = function(block) { var touch_var = Blockly.Lua.variableDB_.getDistinctName('e' + dropdown_electrode + '_touch', Blockly.Variables.NAME_TYPE); - var code = 'local ' + touch_var + ' = Hardware:cap_get_touched()\n'; + var code = 'local ' + touch_var + ' = Hardware.Capacitive:get_touched()\n'; code += touch_var + ' = bit.band(' + touch_var + ', 2^' + dropdown_electrode + ') > 0\n'; if(statements_body_tou == '' && statements_body_rel == ''){ diff --git a/src/opsoro/config/default.conf b/src/opsoro/config/default.conf index 2befe01..907050c 100644 --- a/src/opsoro/config/default.conf +++ b/src/opsoro/config/default.conf @@ -1,5 +1,5 @@ { - "name": "Ono robot", + "name": "OPSORO robot", "skin": "ono", "grid": "18", "modules": [ @@ -7,83 +7,52 @@ "module": "eyebrow", "name": "eyebrow_left", "canvas": { - "x": 0.2007176817525277, - "y": -0.6989197159364468, - "width": 0.19997291766971595, - "height": 0.02888781896966779, + "x": 0.2007168458781363, + "y": -0.6989247311827956, + "width": 0.22470495672698665, + "height": 0.185051140833989, "rotation": 0 }, "dofs": [ { - "name": "left_vertical", - "servo": { - "pin": 15, - "mid": 1550, - "min": 200, - "max": -250 - }, - "mapping": { - "neutral": 0.0, - "poly": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - -0.25, - -0.50, - -0.25, - -0.25, - -0.25, - -0.25, - 0.0, - 0.25, - 0.25 - ] - } + "name": "left_vertical" + }, + { + "name": "right_vertical" }, { - "name": "right_vertical", + "name": "rotation", "servo": { - "pin": 14, - "mid": 1525, - "min": -200, - "max": 300 + "pin": "11", + "mid": "1550", + "min": "300", + "max": "-300" }, "mapping": { - "neutral": 0.0, + "neutral": "0", "poly": [ - 0.25, - 0.50, - 0.70, - 0.70, - 0.70, - 0.70, - 0.50, - 0.25, - -0.50, - -0.50, - -0.25, - 0.25, - 0.25, - -0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.50 + 0.3, + 0.5, + 0.7, + 0.5, + 0.15, + -0.15, + -0.45, + -0.7, + -1, + -0.65, + -0.35, + 0, + 0.25, + 0.5, + 0.5, + 0.45, + 0.75, + 1, + 0.7, + 0.25 ] } - }, - { - "name": "rotation" } ] }, @@ -91,62 +60,112 @@ "module": "eye", "name": "eye_left", "canvas": { - "x": 0.20071684587813632, - "y": -0.49820788530465954, - "width": 0.2, - "height": 0.2, + "x": 0.2007168458781363, + "y": -0.4982078853046595, + "width": 0.23792289535798586, + "height": 0.23792289535798586, "rotation": 0 }, "dofs": [ { "name": "pupil_horizontal", "servo": { - "pin": 13, - "mid": 1550, - "min": -350, - "max": 350 + "pin": "15", + "mid": "1600", + "min": "250", + "max": "-250" + }, + "mapping": { + "neutral": 0, + "poly": [ + 0, + 0, + 0, + 0, + 0, + 0.6, + 0.4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -0.35, + -0.25, + 0, + 0 + ] } }, { "name": "pupil_vertical", "servo": { - "pin": 12, - "mid": 1525, - "min": -350, - "max": 350 + "pin": "14", + "mid": "1500", + "min": "-250", + "max": "250" + }, + "mapping": { + "neutral": 0, + "poly": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -0.3, + -0.5, + -0.7, + -0.5, + -0.4, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] } }, { "name": "eyelid_closure", "servo": { - "pin": 11, - "mid": 1525, - "min": -300, - "max": 350 + "pin": "13", + "mid": "1630", + "min": "-200", + "max": "200" }, "mapping": { - "neutral": 0.5, + "neutral": "0.7", "poly": [ - 0.50, - 0.50, - 0.50, - 0.50, - 0.50, - 0.80, - 0.80, - 0.80, - 0.50, - 0.50, - 0.50, - 0.40, - 0.40, - 0.40, - 0.25, - 0.25, - 0.50, - 0.50, - 0.50, - 0.50 + 0.7, + 1, + 1, + 0.65, + 0.25, + 0, + 0.05, + -0.05, + 0, + -0.05, + -0.15, + -0.35, + -0.65, + -1, + -0.45, + -0.15, + 0.15, + 0.4, + 0.5, + 0.5 ] } } @@ -157,119 +176,88 @@ "name": "mouth", "canvas": { "x": 0, - "y": -0.19712927298988928, - "width": 0.19998796340876263, - "height": 0.17332691381800674, + "y": -0.1971326164874551, + "width": 0.42738001573564127, + "height": 0.20708103855232102, "rotation": 0 }, "dofs": [ { - "name": "left_vertical", + "name": "left_vertical" + }, + { + "name": "middle_vertical" + }, + { + "name": "right_vertical" + }, + { + "name": "left_rotation", "servo": { - "pin": 5, - "mid": 1550, - "min": 400, - "max": -300 + "pin": "10", + "mid": "1550", + "min": "-250", + "max": "250" }, "mapping": { - "neutral": 0.2, + "neutral": "0", "poly": [ - 0.50, - 0.70, - 0.70, - 0.40, - 0.0, - 0.0, - -0.50, - -0.50, - -0.50, - -0.50, - -0.50, - -1.0, - -1.0, + 0.5, + 0.75, + 1, + 0.6, + 0.1, + -0.3, + -0.55, + 0.5, + -0.5, + -0.4, -0.25, + -0.15, + -0.15, -0.25, + -0.55, + -0.1, + 0.15, 0.25, - 0.25, - 0.50, - 0.50, - 0.50 + 0.2, + 0.35 ] } }, { - "name": "middle_vertical", + "name": "right_rotation", "servo": { - "pin": 6, - "mid": 1525, - "min": 400, - "max": -250 + "pin": "5", + "mid": "1550", + "min": "250", + "max": "-250" }, "mapping": { - "neutral": 0.5, + "neutral": "0", "poly": [ - 1.0, - 0.50, - -1.0, - -1.0, - -0.50, - -1.0, - -0.80, - -0.80, - -0.80, - 0.50, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0 - ] - } - }, - { - "name": "right_vertical", - "servo": { - "pin": 7, - "mid": 1600, - "min": -400, - "max": 300 - }, - "mapping": { - "neutral": 0.2, - "poly": [ - 0.50, - 0.70, - 0.70, - 0.40, - 0.0, - 0.0, - -0.50, - -0.50, - -0.50, - -0.50, - -0.50, - -1.0, - -1.0, + 0.5, + 0.75, + 1, + 0.6, + 0.1, + -0.3, + -0.7, + -1, + -0.75, + -0.4, -0.25, + -0.15, + -0.15, -0.25, + -0.1, + -0.1, + 0.15, 0.25, - 0.25, - 0.50, - 0.50, - 0.50 + 0.2, + 0.35 ] } - }, - { - "name": "left_rotation" - }, - { - "name": "right_rotation" } ] }, @@ -277,62 +265,112 @@ "module": "eye", "name": "eye_right", "canvas": { - "x": -0.2007168458781361, - "y": -0.49820788530465954, - "width": 0.2, - "height": 0.2, + "x": -0.20071684587813615, + "y": -0.4982078853046595, + "width": 0.23792289535798586, + "height": 0.23792289535798586, "rotation": 0 }, "dofs": [ { "name": "pupil_horizontal", "servo": { - "pin": 3, - "mid": 1700, - "min": -350, - "max": 350 + "pin": 0, + "mid": "1600", + "min": "250", + "max": "-250" + }, + "mapping": { + "neutral": 0, + "poly": [ + 0, + 0, + 0, + 0, + 0, + -0.6, + -0.4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.35, + 0.25, + 0, + 0 + ] } }, { "name": "pupil_vertical", "servo": { - "pin": 2, - "mid": 1525, - "min": 350, - "max": -350 + "pin": "1", + "mid": "1500", + "min": "-350", + "max": "350" + }, + "mapping": { + "neutral": 0, + "poly": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -0.3, + -0.5, + -0.7, + -0.5, + -0.4, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] } }, { "name": "eyelid_closure", "servo": { - "pin": 4, - "mid": 1500, - "min": 300, - "max": -350 + "pin": "2", + "mid": "1630", + "min": "-200", + "max": "200" }, "mapping": { - "neutral": 0.5, + "neutral": "0.7", "poly": [ - 0.50, - 0.50, - 0.50, - 0.50, - 0.50, - 0.80, - 0.80, - 0.80, - 0.50, - 0.50, - 0.50, - 0.40, - 0.40, - 0.40, - 0.25, - 0.25, - 0.50, - 0.50, - 0.50, - 0.50 + 0.7, + 1, + 1, + 0.65, + 0.25, + 0, + 0.05, + -0.05, + 0, + -0.05, + -0.15, + -0.35, + -0.65, + -1, + -0.45, + -0.15, + 0.15, + 0.4, + 0.5, + 0.5 ] } } @@ -342,83 +380,52 @@ "module": "eyebrow", "name": "eyebrow_right", "canvas": { - "x": -0.20071015888300434, - "y": -0.6989197159364468, - "width": 0.19998796340876263, - "height": 0.02888781896966779, + "x": -0.20071684587813615, + "y": -0.6989247311827956, + "width": 0.22470495672698665, + "height": 0.185051140833989, "rotation": 0 }, "dofs": [ { - "name": "left_vertical", - "servo": { - "pin": 0, - "mid": 1625, - "min": 200, - "max": -300 - }, - "mapping": { - "neutral": 0, - "poly": [ - 0.25, - 0.50, - 0.70, - 0.70, - 0.70, - 0.70, - 0.50, - 0.25, - -0.50, - -0.50, - -0.25, - 0.25, - 0.25, - -0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.50 - ] - } + "name": "left_vertical" }, { - "name": "right_vertical", + "name": "right_vertical" + }, + { + "name": "rotation", "servo": { - "pin": 1, - "mid": 1625, - "min": -200, - "max": 250 + "pin": "4", + "mid": "1550", + "min": "300", + "max": "-300" }, "mapping": { - "neutral": 0, + "neutral": "0", "poly": [ - 0.0, - 0.0, - 0.0, - 0.0, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - 0.25, - -0.25, - -0.50, + -0.3, + -0.5, + -0.7, + -0.5, + -0.15, + 0.15, + 0.45, + 0.7, + 1, + 0.65, + 0.35, + 0, -0.25, - -0.25, - -0.25, - -0.25, - 0.0, - 0.25, - 0.25 + -0.5, + -0.5, + -0.45, + -0.75, + -1, + -0.7, + -0.25 ] } - }, - { - "name": "rotation" } ] } diff --git a/src/opsoro/config/default_grid.conf b/src/opsoro/config/default_grid.conf index 907050c..60ef229 100644 --- a/src/opsoro/config/default_grid.conf +++ b/src/opsoro/config/default_grid.conf @@ -71,9 +71,9 @@ "name": "pupil_horizontal", "servo": { "pin": "15", - "mid": "1600", - "min": "250", - "max": "-250" + "mid": "1470", + "min": "300", + "max": "-300" }, "mapping": { "neutral": 0, @@ -105,9 +105,9 @@ "name": "pupil_vertical", "servo": { "pin": "14", - "mid": "1500", - "min": "-250", - "max": "250" + "mid": "1470", + "min": "-300", + "max": "300" }, "mapping": { "neutral": 0, @@ -139,9 +139,9 @@ "name": "eyelid_closure", "servo": { "pin": "13", - "mid": "1630", - "min": "-200", - "max": "200" + "mid": "1300", + "min": "-400", + "max": "450" }, "mapping": { "neutral": "0.7", @@ -276,9 +276,9 @@ "name": "pupil_horizontal", "servo": { "pin": 0, - "mid": "1600", - "min": "250", - "max": "-250" + "mid": "1470", + "min": "300", + "max": "-300" }, "mapping": { "neutral": 0, @@ -310,9 +310,9 @@ "name": "pupil_vertical", "servo": { "pin": "1", - "mid": "1500", - "min": "-350", - "max": "350" + "mid": "1470", + "min": "-300", + "max": "300" }, "mapping": { "neutral": 0, @@ -344,9 +344,9 @@ "name": "eyelid_closure", "servo": { "pin": "2", - "mid": "1630", - "min": "-200", - "max": "200" + "mid": "1300", + "min": "-400", + "max": "450" }, "mapping": { "neutral": "0.7", diff --git a/src/opsoro/config/default_ono.conf b/src/opsoro/config/default_ono.conf new file mode 100644 index 0000000..2befe01 --- /dev/null +++ b/src/opsoro/config/default_ono.conf @@ -0,0 +1,426 @@ +{ + "name": "Ono robot", + "skin": "ono", + "grid": "18", + "modules": [ + { + "module": "eyebrow", + "name": "eyebrow_left", + "canvas": { + "x": 0.2007176817525277, + "y": -0.6989197159364468, + "width": 0.19997291766971595, + "height": 0.02888781896966779, + "rotation": 0 + }, + "dofs": [ + { + "name": "left_vertical", + "servo": { + "pin": 15, + "mid": 1550, + "min": 200, + "max": -250 + }, + "mapping": { + "neutral": 0.0, + "poly": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + -0.25, + -0.50, + -0.25, + -0.25, + -0.25, + -0.25, + 0.0, + 0.25, + 0.25 + ] + } + }, + { + "name": "right_vertical", + "servo": { + "pin": 14, + "mid": 1525, + "min": -200, + "max": 300 + }, + "mapping": { + "neutral": 0.0, + "poly": [ + 0.25, + 0.50, + 0.70, + 0.70, + 0.70, + 0.70, + 0.50, + 0.25, + -0.50, + -0.50, + -0.25, + 0.25, + 0.25, + -0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.50 + ] + } + }, + { + "name": "rotation" + } + ] + }, + { + "module": "eye", + "name": "eye_left", + "canvas": { + "x": 0.20071684587813632, + "y": -0.49820788530465954, + "width": 0.2, + "height": 0.2, + "rotation": 0 + }, + "dofs": [ + { + "name": "pupil_horizontal", + "servo": { + "pin": 13, + "mid": 1550, + "min": -350, + "max": 350 + } + }, + { + "name": "pupil_vertical", + "servo": { + "pin": 12, + "mid": 1525, + "min": -350, + "max": 350 + } + }, + { + "name": "eyelid_closure", + "servo": { + "pin": 11, + "mid": 1525, + "min": -300, + "max": 350 + }, + "mapping": { + "neutral": 0.5, + "poly": [ + 0.50, + 0.50, + 0.50, + 0.50, + 0.50, + 0.80, + 0.80, + 0.80, + 0.50, + 0.50, + 0.50, + 0.40, + 0.40, + 0.40, + 0.25, + 0.25, + 0.50, + 0.50, + 0.50, + 0.50 + ] + } + } + ] + }, + { + "module": "mouth", + "name": "mouth", + "canvas": { + "x": 0, + "y": -0.19712927298988928, + "width": 0.19998796340876263, + "height": 0.17332691381800674, + "rotation": 0 + }, + "dofs": [ + { + "name": "left_vertical", + "servo": { + "pin": 5, + "mid": 1550, + "min": 400, + "max": -300 + }, + "mapping": { + "neutral": 0.2, + "poly": [ + 0.50, + 0.70, + 0.70, + 0.40, + 0.0, + 0.0, + -0.50, + -0.50, + -0.50, + -0.50, + -0.50, + -1.0, + -1.0, + -0.25, + -0.25, + 0.25, + 0.25, + 0.50, + 0.50, + 0.50 + ] + } + }, + { + "name": "middle_vertical", + "servo": { + "pin": 6, + "mid": 1525, + "min": 400, + "max": -250 + }, + "mapping": { + "neutral": 0.5, + "poly": [ + 1.0, + 0.50, + -1.0, + -1.0, + -0.50, + -1.0, + -0.80, + -0.80, + -0.80, + 0.50, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0 + ] + } + }, + { + "name": "right_vertical", + "servo": { + "pin": 7, + "mid": 1600, + "min": -400, + "max": 300 + }, + "mapping": { + "neutral": 0.2, + "poly": [ + 0.50, + 0.70, + 0.70, + 0.40, + 0.0, + 0.0, + -0.50, + -0.50, + -0.50, + -0.50, + -0.50, + -1.0, + -1.0, + -0.25, + -0.25, + 0.25, + 0.25, + 0.50, + 0.50, + 0.50 + ] + } + }, + { + "name": "left_rotation" + }, + { + "name": "right_rotation" + } + ] + }, + { + "module": "eye", + "name": "eye_right", + "canvas": { + "x": -0.2007168458781361, + "y": -0.49820788530465954, + "width": 0.2, + "height": 0.2, + "rotation": 0 + }, + "dofs": [ + { + "name": "pupil_horizontal", + "servo": { + "pin": 3, + "mid": 1700, + "min": -350, + "max": 350 + } + }, + { + "name": "pupil_vertical", + "servo": { + "pin": 2, + "mid": 1525, + "min": 350, + "max": -350 + } + }, + { + "name": "eyelid_closure", + "servo": { + "pin": 4, + "mid": 1500, + "min": 300, + "max": -350 + }, + "mapping": { + "neutral": 0.5, + "poly": [ + 0.50, + 0.50, + 0.50, + 0.50, + 0.50, + 0.80, + 0.80, + 0.80, + 0.50, + 0.50, + 0.50, + 0.40, + 0.40, + 0.40, + 0.25, + 0.25, + 0.50, + 0.50, + 0.50, + 0.50 + ] + } + } + ] + }, + { + "module": "eyebrow", + "name": "eyebrow_right", + "canvas": { + "x": -0.20071015888300434, + "y": -0.6989197159364468, + "width": 0.19998796340876263, + "height": 0.02888781896966779, + "rotation": 0 + }, + "dofs": [ + { + "name": "left_vertical", + "servo": { + "pin": 0, + "mid": 1625, + "min": 200, + "max": -300 + }, + "mapping": { + "neutral": 0, + "poly": [ + 0.25, + 0.50, + 0.70, + 0.70, + 0.70, + 0.70, + 0.50, + 0.25, + -0.50, + -0.50, + -0.25, + 0.25, + 0.25, + -0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.50 + ] + } + }, + { + "name": "right_vertical", + "servo": { + "pin": 1, + "mid": 1625, + "min": -200, + "max": 250 + }, + "mapping": { + "neutral": 0, + "poly": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + 0.25, + -0.25, + -0.50, + -0.25, + -0.25, + -0.25, + -0.25, + 0.0, + 0.25, + 0.25 + ] + } + }, + { + "name": "rotation" + } + ] + } + ] +} diff --git a/src/opsoro/config/grid_pin.txt b/src/opsoro/config/grid_pin.txt new file mode 100644 index 0000000..8799a6c --- /dev/null +++ b/src/opsoro/config/grid_pin.txt @@ -0,0 +1,17 @@ +eye_right: + pupil_horizontal: servo pin: 0, + pupil_vertical: servo pin: 1, + eyelid_closure: servo pin": 2, + +eyebrow_right: servo pin: 4, + +mouth: + right_rotation: servo pin: 5, + left_rotation: servo pin: 10, + +eyebrow_left: servo pin: 11, + +eye_left: + pupil_horizontal: servo pin: 15, + pupil_vertical: servo pin: 14, + eyelid_closure: servo pin": 13, diff --git a/src/opsoro/config/preferences.yaml b/src/opsoro/config/preferences.yaml index 78c88e7..e9592a7 100644 --- a/src/opsoro/config/preferences.yaml +++ b/src/opsoro/config/preferences.yaml @@ -1,9 +1,9 @@ general: - robot_name: Ono + robot_name: robot password: opsoro123 alive: - enabled: true + enabled: false aliveness: 30 blink: true gaze: true @@ -11,8 +11,8 @@ alive: audio: master_volume: 60 tts_engine: espeak - tts_language: nl - tts_gender: m + tts_language: en + tts_gender: f wireless: ssid: OPSORO-bot diff --git a/src/opsoro/console_msg.py b/src/opsoro/console_msg.py index 0753459..768c01c 100644 --- a/src/opsoro/console_msg.py +++ b/src/opsoro/console_msg.py @@ -1,22 +1,26 @@ def print_info(msg): - print "\033[1m[\033[96m INFO \033[0m\033[1m]\033[0m %s" % msg + print("\033[1m[\033[96m INFO \033[0m\033[1m]\033[0m %s" % msg) def print_warning(msg): - print "\033[1m[\033[93m WARN \033[0m\033[1m]\033[0m %s" % msg + print("\033[1m[\033[93m WARN \033[0m\033[1m]\033[0m %s" % msg) def print_error(msg): - print "\033[1m[\033[91m ERRO \033[0m\033[1m]\033[0m %s" % msg + print("\033[1m[\033[91m ERRO \033[0m\033[1m]\033[0m %s" % msg) def print_apploaded(appname): - print "\033[1m[\033[92m APP LOADED \033[0m\033[1m]\033[0m %s" % appname + print("\033[1m[\033[92m APP LOADED \033[0m\033[1m]\033[0m %s" % appname) def print_appstarted(appname): - print "\033[1m[\033[92m APP STARTED \033[0m\033[1m]\033[0m %s" % appname + print("\033[1m[\033[92m APP STARTED \033[0m\033[1m]\033[0m %s" % appname) def print_appstopped(appname): - print "\033[1m[\033[93m APP STOPPED \033[0m\033[1m]\033[0m %s" % appname + print("\033[1m[\033[93m APP STOPPED \033[0m\033[1m]\033[0m %s" % appname) + + +def print_spi(msg): + print("\033[1m[\033[94m SPI \033[0m\033[1m]\033[0m %s" % msg) diff --git a/src/opsoro/data/lua_scripting/scripts/CanvasPitch.lua b/src/opsoro/data/lua_scripting/scripts/CanvasPitch.lua index 944f65e..b88c6e9 100644 --- a/src/opsoro/data/lua_scripting/scripts/CanvasPitch.lua +++ b/src/opsoro/data/lua_scripting/scripts/CanvasPitch.lua @@ -35,8 +35,8 @@ function setup() Sound:say_tts("But usually I'm very happy!", true) -- Initialize hardware and expressions - Hardware:servo_init() - Hardware:servo_neutral() + Hardware.Servo:init() + Hardware.Servo:neutral() Expression.dofs.r_e_lid.add_overlay(blink_overlay) Expression.dofs.l_e_lid.add_overlay(blink_overlay) @@ -44,7 +44,7 @@ function setup() Expression:set_emotion_r_phi(1.0, 15, true, 1.5) Expression.update() - Hardware:servo_enable() + Hardware.Servo:enable() -- Run demo scenario lipsync("Hello, my name is Ono", 1.6, {0.1, 0.45, 0.8}) @@ -101,5 +101,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/EdgeHue.lua b/src/opsoro/data/lua_scripting/scripts/EdgeHue.lua index b790c4f..b830e46 100644 --- a/src/opsoro/data/lua_scripting/scripts/EdgeHue.lua +++ b/src/opsoro/data/lua_scripting/scripts/EdgeHue.lua @@ -7,8 +7,8 @@ function setup() UI:init() UI:add_key("up") UI:add_key("down") - Hardware:neo_init(8) - Hardware:neo_set_brightness(50) + Hardware.Neopixel:init(8) + Hardware.Neopixel:set_brightness(50) end function loop() @@ -34,12 +34,12 @@ end function change_color() local hue = math.floor(map(hue_pos, 0, 20, 0, 255)) --local hue = 30 - Hardware:neo_set_all_hsv(hue, 255, 255) - Hardware:neo_show() + Hardware.Neopixel:set_all_hsv(hue, 255, 255) + Hardware.Neopixel:show() end function quit() -- Called when the script is stopped - Hardware:neo_set_all(0, 0, 0) - Hardware:neo_show() + Hardware.Neopixel:set_all(0, 0, 0) + Hardware.Neopixel:show() end diff --git a/src/opsoro/data/lua_scripting/scripts/EmotionButton.lua b/src/opsoro/data/lua_scripting/scripts/EmotionButton.lua index 2cad284..e8b27e4 100644 --- a/src/opsoro/data/lua_scripting/scripts/EmotionButton.lua +++ b/src/opsoro/data/lua_scripting/scripts/EmotionButton.lua @@ -1,18 +1,18 @@ function setup() - Hardware:servo_init() - Hardware:servo_enable() - + Hardware.Servo:init() + Hardware.Servo:enable() + Expression:set_emotion_r_phi(0.0, 0.00) Expression:update() end function loop() - if Hardware:ana_read_channel(1) > 1000 then + if Hardware.Analog:read_channel(1) > 1000 then Expression:set_emotion_r_phi(1.0, 20, true) Expression:update() sleep(0.5) end - if Hardware:ana_read_channel(0) > 1000 then + if Hardware.Analog:read_channel(0) > 1000 then Expression:set_emotion_r_phi(1.0, 200, true) Expression:update() sleep(0.5) @@ -20,5 +20,5 @@ function loop() end function quit() - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/EyeButton.lua b/src/opsoro/data/lua_scripting/scripts/EyeButton.lua index 1eff788..96f18fd 100644 --- a/src/opsoro/data/lua_scripting/scripts/EyeButton.lua +++ b/src/opsoro/data/lua_scripting/scripts/EyeButton.lua @@ -10,16 +10,16 @@ function setup() UI:init() UI:add_key("left") UI:add_key("right") - - Hardware:servo_init() - Hardware:servo_neutral() + + Hardware.Servo:init() + Hardware.Servo:neutral() Expression.dofs.r_e_hor.add_overlay(eye_overlay) Expression.dofs.l_e_hor.add_overlay(eye_overlay) Expression:set_emotion_r_phi(1.0, 15, true, 1.5) - + Expression.update() - Hardware:servo_enable() + Hardware.Servo:enable() end function loop() @@ -38,5 +38,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/HRI2016.lua b/src/opsoro/data/lua_scripting/scripts/HRI2016.lua index 610864d..cc382eb 100644 --- a/src/opsoro/data/lua_scripting/scripts/HRI2016.lua +++ b/src/opsoro/data/lua_scripting/scripts/HRI2016.lua @@ -35,8 +35,8 @@ function setup() Sound:say_tts("But usually I'm very happy!", true) -- Initialize hardware and expressions - Hardware:servo_init() - Hardware:servo_neutral() + Hardware.Servo:init() + Hardware.Servo:neutral() Expression.dofs.r_e_lid.add_overlay(blink_overlay) Expression.dofs.l_e_lid.add_overlay(blink_overlay) @@ -44,7 +44,7 @@ function setup() Expression:set_emotion_r_phi(1.0, 15, true, 1.5) Expression.update() - Hardware:servo_enable() + Hardware.Servo:enable() -- Run demo scenario while true do @@ -102,5 +102,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/HRI2016b.lua b/src/opsoro/data/lua_scripting/scripts/HRI2016b.lua index 610864d..cc382eb 100644 --- a/src/opsoro/data/lua_scripting/scripts/HRI2016b.lua +++ b/src/opsoro/data/lua_scripting/scripts/HRI2016b.lua @@ -35,8 +35,8 @@ function setup() Sound:say_tts("But usually I'm very happy!", true) -- Initialize hardware and expressions - Hardware:servo_init() - Hardware:servo_neutral() + Hardware.Servo:init() + Hardware.Servo:neutral() Expression.dofs.r_e_lid.add_overlay(blink_overlay) Expression.dofs.l_e_lid.add_overlay(blink_overlay) @@ -44,7 +44,7 @@ function setup() Expression:set_emotion_r_phi(1.0, 15, true, 1.5) Expression.update() - Hardware:servo_enable() + Hardware.Servo:enable() -- Run demo scenario while true do @@ -102,5 +102,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/NeoBlink.lua b/src/opsoro/data/lua_scripting/scripts/NeoBlink.lua index c4d51f3..0fda62d 100644 --- a/src/opsoro/data/lua_scripting/scripts/NeoBlink.lua +++ b/src/opsoro/data/lua_scripting/scripts/NeoBlink.lua @@ -1,21 +1,21 @@ function setup() -- Called once, when the script is started print("Starting NeoBlink...") - Hardware.neo_init(8) + Hardware.Neopixel:init(8) end function loop() -- Called repeatedly, put your main program here - Hardware.neo_set_all(75, 75, 0) - Hardware.neo_show() + Hardware.Neopixel:set_all(75, 75, 0) + Hardware.Neopixel:show() sleep(1) - Hardware.neo_set_all(0, 75, 75) - Hardware.neo_show() + Hardware.Neopixel:set_all(0, 75, 75) + Hardware.Neopixel:show() sleep(1) end function quit() -- Called when the script is stopped - Hardware.neo_set_all(0, 0, 0) - Hardware.neo_show() + Hardware.Neopixel:set_all(0, 0, 0) + Hardware.Neopixel:show() end diff --git a/src/opsoro/data/lua_scripting/scripts/NeoButtons.lua b/src/opsoro/data/lua_scripting/scripts/NeoButtons.lua index ad90a0b..228db9b 100644 --- a/src/opsoro/data/lua_scripting/scripts/NeoButtons.lua +++ b/src/opsoro/data/lua_scripting/scripts/NeoButtons.lua @@ -10,38 +10,38 @@ function setup() UI:add_key("left") UI:add_key("right") - Hardware:neo_init(8) - Hardware:neo_set_all(0, 0, 0) - Hardware:neo_show() + Hardware:Neopixel:init(8) + Hardware:Neopixel:set_all(0, 0, 0) + Hardware:Neopixel:show() end function loop() -- Called repeatedly, put your main program here if UI:is_key_pressed("up") then - Hardware:neo_set_pixel(0, 75, 0, 0) + Hardware:Neopixel:set_pixel(0, 75, 0, 0) else - Hardware:neo_set_pixel(0, 0, 0, 0) + Hardware:Neopixel:set_pixel(0, 0, 0, 0) end if UI:is_key_pressed("down") then - Hardware:neo_set_pixel(1, 75, 75, 0) + Hardware:Neopixel:set_pixel(1, 75, 75, 0) else - Hardware:neo_set_pixel(1, 0, 0, 0) + Hardware:Neopixel:set_pixel(1, 0, 0, 0) end if UI:is_key_pressed("left") then - Hardware:neo_set_pixel(2, 0, 75, 0) + Hardware:Neopixel:set_pixel(2, 0, 75, 0) else - Hardware:neo_set_pixel(2, 0, 0, 0) + Hardware:Neopixel:set_pixel(2, 0, 0, 0) end if UI:is_key_pressed("right") then - Hardware:neo_set_pixel(3, 0, 75, 75) + Hardware:Neopixel:set_pixel(3, 0, 75, 75) else - Hardware:neo_set_pixel(3, 0, 0, 0) + Hardware:Neopixel:set_pixel(3, 0, 0, 0) end - Hardware:neo_show() + Hardware:Neopixel:show() end function quit() -- Called when the script is stopped - Hardware:neo_set_all(0, 0, 0) - Hardware:neo_show() + Hardware:Neopixel:set_all(0, 0, 0) + Hardware:Neopixel:show() end diff --git a/src/opsoro/data/lua_scripting/scripts/NeoKeypad.lua b/src/opsoro/data/lua_scripting/scripts/NeoKeypad.lua index eff1464..0c7f444 100644 --- a/src/opsoro/data/lua_scripting/scripts/NeoKeypad.lua +++ b/src/opsoro/data/lua_scripting/scripts/NeoKeypad.lua @@ -6,26 +6,26 @@ num_electrodes = 12 function setup() -- Called once, when the script is started print("Starting NeoPixel Keypad...") - Hardware:neo_init(num_pixels) - Hardware:cap_init(num_electrodes) + Hardware.Neopixel:init(num_pixels) + Hardware.Capacitive:init(num_electrodes) end function loop() -- Called repeatedly, put your main program here - local touchData = Hardware:cap_get_touched() + local touchData = Hardware.Capacitive:get_touched() - Hardware:neo_set_all(0, 0, 0) + Hardware.Neopixel:set_all(0, 0, 0) for i=0,7 do if bit32.extract(touchData, i) > 0 then - Hardware:neo_set_pixel(i, 75, 75, 0) + Hardware.Neopixel:set_pixel(i, 75, 75, 0) end end - Hardware:neo_show() + Hardware.Neopixel:show() end function quit() -- Called when the script is stopped - Hardware:neo_set_all(0, 0, 0) - Hardware:neo_show() + Hardware.Neopixel:set_all(0, 0, 0) + Hardware.Neopixel:show() end diff --git a/src/opsoro/data/lua_scripting/scripts/ONA_testing_1_1.lua b/src/opsoro/data/lua_scripting/scripts/ONA_testing_1_1.lua index e25c9b6..f8335c9 100644 --- a/src/opsoro/data/lua_scripting/scripts/ONA_testing_1_1.lua +++ b/src/opsoro/data/lua_scripting/scripts/ONA_testing_1_1.lua @@ -35,8 +35,8 @@ function setup() Sound:say_tts("I'm very happy today!", true) -- Initialize hardware and expressions - Hardware:servo_init() - Hardware:servo_neutral() + Hardware:Servo:init() + Hardware:Servo:neutral() Expression.dofs.r_e_lid.add_overlay(blink_overlay) Expression.dofs.l_e_lid.add_overlay(blink_overlay) @@ -44,7 +44,7 @@ function setup() Expression:set_emotion_r_phi(1.0, 15, true, 1.5) Expression.update() - Hardware:servo_enable() + Hardware:Servo:enable() -- Run demo scenario lipsync("Hello, my name is Lola", 1.6, {0.1, 0.45, 0.8}) @@ -100,5 +100,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware:Servo:disable() end \ No newline at end of file diff --git a/src/opsoro/data/lua_scripting/scripts/introduction.lua b/src/opsoro/data/lua_scripting/scripts/introduction.lua index 349e93e..e62db85 100644 --- a/src/opsoro/data/lua_scripting/scripts/introduction.lua +++ b/src/opsoro/data/lua_scripting/scripts/introduction.lua @@ -35,8 +35,8 @@ function setup() Sound:say_tts("But usually I'm very happy!", true) -- Initialize hardware and expressions - Hardware:servo_init() - Hardware:servo_neutral() + Hardware:Servo:init() + Hardware:Servo:neutral() Expression.dofs.r_e_lid.add_overlay(blink_overlay) Expression.dofs.l_e_lid.add_overlay(blink_overlay) @@ -44,7 +44,7 @@ function setup() Expression:set_emotion_r_phi(1.0, 15, true, 1.5) Expression.update() - Hardware:servo_enable() + Hardware:Servo:enable() -- Run demo scenario lipsync("Hello, my name is Ono", 1.6, {0.1, 0.45, 0.8}) @@ -100,5 +100,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware:Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/old/qsddsqfdssqdf.lua b/src/opsoro/data/lua_scripting/scripts/old/qsddsqfdssqdf.lua index fce7011..50e957a 100644 --- a/src/opsoro/data/lua_scripting/scripts/old/qsddsqfdssqdf.lua +++ b/src/opsoro/data/lua_scripting/scripts/old/qsddsqfdssqdf.lua @@ -6,13 +6,13 @@ function setup() UI:add_key("down") UI:add_key("x") UI:add_key("space") - Hardware:cap_init(8) + Hardware:Capacitive:init(8) end function loop() -- Called repeatedly, put your main program here if rising_edge("space", UI:is_key_pressed("space")) then - print("E0: " .. Hardware:cap_get_baseline_data(5)) + print("E0: " .. Hardware:Capacitive:get_baseline_data(5)) end end diff --git a/src/opsoro/data/lua_scripting/scripts/step10.lua b/src/opsoro/data/lua_scripting/scripts/step10.lua index ea8a577..71129ff 100644 --- a/src/opsoro/data/lua_scripting/scripts/step10.lua +++ b/src/opsoro/data/lua_scripting/scripts/step10.lua @@ -4,13 +4,13 @@ function setup() UI:add_key("up") UI:add_key("down") - Hardware:servo_init() - Hardware:servo_neutral() + Hardware.Servo:init() + Hardware.Servo:neutral() Expression:set_emotion_val_ar(0.0, 0.0) Expression.update() - Hardware:servo_enable() + Hardware.Servo:enable() end function loop() @@ -30,5 +30,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware.Servo:disable() end diff --git a/src/opsoro/data/lua_scripting/scripts/step11.lua b/src/opsoro/data/lua_scripting/scripts/step11.lua index a91e024..edf181c 100644 --- a/src/opsoro/data/lua_scripting/scripts/step11.lua +++ b/src/opsoro/data/lua_scripting/scripts/step11.lua @@ -4,13 +4,13 @@ function setup() UI:add_key("up") UI:add_key("down") - Hardware:servo_init() - Hardware:servo_neutral() + Hardware:Servo:init() + Hardware:Servo:neutral() Expression:set_emotion_val_ar(0.0, 0.0) Expression.update() - Hardware:servo_enable() + Hardware:Servo:enable() end function loop() @@ -30,5 +30,5 @@ end function quit() -- Called when the script is stopped - Hardware:servo_disable() + Hardware:Servo:disable() end diff --git a/src/opsoro/data/visual_programming/scripts/currentscript.xml.tmp b/src/opsoro/data/visual_programming/scripts/currentscript.xml.tmp index 243fffc..2856f37 100644 --- a/src/opsoro/data/visual_programming/scripts/currentscript.xml.tmp +++ b/src/opsoro/data/visual_programming/scripts/currentscript.xml.tmp @@ -1 +1 @@ -64#ff0000128i0641#000000i#33cc00MINUSi10.1i0641#3333ffi#ff0000MINUSi10.1#000000 \ No newline at end of file + \ No newline at end of file diff --git a/src/opsoro/dof/servo.py b/src/opsoro/dof/servo.py index d03c3a0..9d2fe6e 100644 --- a/src/opsoro/dof/servo.py +++ b/src/opsoro/dof/servo.py @@ -82,6 +82,6 @@ def update(self): if self.pin is not None: with Hardware.lock: - Hardware.servo_set(self.pin, self.position) + Hardware.Servo.set(self.pin, self.position) # return True return dof_animation_changed diff --git a/src/opsoro/hardware/SPI_commands.txt b/src/opsoro/hardware/SPI_commands.txt new file mode 100644 index 0000000..8e0c927 --- /dev/null +++ b/src/opsoro/hardware/SPI_commands.txt @@ -0,0 +1,52 @@ +### SPI COMMANDS + +# > GENERAL IN OUT +CMD_NOP = 0 # 0 0 No operation +CMD_PING = 1 # 0 1 To check connection +CMD_READ = 2 # 0 ? Return result from previous command +CMD_RESET = 3 # 0 0 Reset the ATmega328 +CMD_LEDON = 4 # 0 0 Turn LED on +CMD_LEDOFF = 5 # 0 0 Turn LED off +CMD_NC = 255 # 0 0 Not connected + +# > I2C IN OUT +CMD_I2C_DETECT = 20 # 1 1 Test if there's a device at addr +CMD_I2C_READ8 = 21 # 2 1 Read byte +CMD_I2C_WRITE8 = 22 # 3 0 Write byte +CMD_I2C_READ16 = 23 # 2 2 Read 2 bytes +CMD_I2C_WRITE16 = 24 # 4 0 Write 2 bytes + +# > SERVO IN OUT +CMD_SERVO_INIT = 40 # 0 0 Init PCA9685 +CMD_SERVO_ENABLE = 41 # 0 0 Turn on MOSFET +CMD_SERVO_DISABLE = 42 # 0 0 Turn off MOSFET +CMD_SERVO_NEUTRAL = 43 # 0 0 Set all servos to 1500 +CMD_SERVO_SET = 44 # 3 0 Set 1 servo position +CMD_SERVO_SETALL = 45 # 32 0 Set position of all servos + +# > CAPACITIVE TOUCH IN OUT +CMD_CAP_INIT = 60 # 3 0 Init MPR121 +CMD_CAP_SETTH = 61 # 3 0 Set pin touch/release threshold +CMD_CAP_GETFD = 62 # 0 24 Get pin filtered data (10 bits per electrode) +CMD_CAP_GETBD = 63 # 1 1 Get pin baseline data, high 8 bits of 10 +CMD_CAP_TOUCHED = 64 # 0 2 Get touched status +CMD_CAP_SETGPIO = 65 # 2 0 Set GPIO mode +CMD_CAP_GPIOREAD = 66 # 0 1 Read GPIO pin +CMD_CAP_GPIOWRITE = 67 # 2 0 Write GPIO pin + +# > NEOPIXEL IN OUT +CMD_NEO_INIT = 80 # 1 0 Init Neopixel +CMD_NEO_ENABLE = 81 # 0 0 Turn on MOSFET +CMD_NEO_DISABLE = 82 # 0 0 Turn off MOSFET +CMD_NEO_SETBRIGHT = 83 # 1 0 Set brightness +CMD_NEO_SHOW = 84 # 0 0 Show pixels +CMD_NEO_SET = 85 # 4 0 Set single pixel +CMD_NEO_SETRANGE = 86 # 5 0 Set range of pixels +CMD_NEO_SETALL = 87 # 3 0 Set all pixels +CMD_NEO_SETHSV = 88 # 4 0 Set single pixel HSV +CMD_NEO_SETRANGEHSV = 89 # 5 0 Set range of pixels HSV +CMD_NEO_SETALLHSV = 90 # 3 0 Set all pixels HSV + +# > ANALOG IN OUT +CMD_ANA_GET = 100 # 1 2 Read an analog channel +CMD_ANA_GETALL = 101 # 0 8 Read all analog channels diff --git a/src/opsoro/hardware/__init__.py b/src/opsoro/hardware/__init__.py index 984f276..0e2053c 100644 --- a/src/opsoro/hardware/__init__.py +++ b/src/opsoro/hardware/__init__.py @@ -1,78 +1,23 @@ -""" -This module defines the interface for communicating with the shield. - -.. autoclass:: _Hardware - :members: - :undoc-members: - :show-inheritance: -""" - import time -import spidev import threading -# SPI COMMANDS # > GENERAL IN OUT CMD_NOP = 0 # 0 0 No operation CMD_NC = 255 # 0 0 Not connected CMD_PING = 1 # 0 1 To check connection -CMD_READ = 2 # 0 ? Return result from previous command CMD_RESET = 3 # 0 0 Reset the ATmega328 CMD_LEDON = 4 # 0 0 Turn LED on CMD_LEDOFF = 5 # 0 0 Turn LED off -# > I2C IN OUT -CMD_I2C_DETECT = 20 # 1 1 Test if there's a device at addr -CMD_I2C_READ8 = 21 # 2 1 Read byte -CMD_I2C_WRITE8 = 22 # 3 0 Write byte -CMD_I2C_READ16 = 23 # 2 2 Read 2 bytes -CMD_I2C_WRITE16 = 24 # 4 0 Write 2 bytes - -# > SERVO IN OUT -CMD_SERVO_INIT = 40 # 0 0 Init PCA9685 -CMD_SERVO_ENABLE = 41 # 0 0 Turn on MOSFET -CMD_SERVO_DISABLE = 42 # 0 0 Turn off MOSFET -CMD_SERVO_NEUTRAL = 43 # 0 0 Set all servos to 1500 -CMD_SERVO_SET = 44 # 3 0 Set 1 servo position -CMD_SERVO_SETALL = 45 # 32 0 Set position of all servos - -# > CAPACITIVE TOUCH IN OUT -CMD_CAP_INIT = 60 # 3 0 Init MPR121 -CMD_CAP_SETTH = 61 # 3 0 Set pin touch/release threshold -CMD_CAP_GETFD = 62 # 0 24 Get pin filtered data (10 bits per electrode) -CMD_CAP_GETBD = 63 # 1 1 Get pin baseline data, high 8 bits of 10 -CMD_CAP_TOUCHED = 64 # 0 2 Get touched status -CMD_CAP_SETGPIO = 65 # 2 0 Set GPIO mode -CMD_CAP_GPIOREAD = 66 # 0 1 Read GPIO pin -CMD_CAP_GPIOWRITE = 67 # 2 0 Write GPIO pin - -# > NEOPIXEL IN OUT -CMD_NEO_INIT = 80 # 1 0 Init Neopixel -CMD_NEO_ENABLE = 81 # 0 0 Turn on MOSFET -CMD_NEO_DISABLE = 82 # 0 0 Turn off MOSFET -CMD_NEO_SETBRIGHT = 83 # 1 0 Set brightness -CMD_NEO_SHOW = 84 # 0 0 Show pixels -CMD_NEO_SET = 85 # 4 0 Set single pixel -CMD_NEO_SETRANGE = 86 # 5 0 Set range of pixels -CMD_NEO_SETALL = 87 # 3 0 Set all pixels -CMD_NEO_SETHSV = 88 # 4 0 Set single pixel HSV -CMD_NEO_SETRANGEHSV = 89 # 5 0 Set range of pixels HSV -CMD_NEO_SETALLHSV = 90 # 3 0 Set all pixels HSV -# > ANALOG IN OUT -CMD_ANA_GET = 100 # 1 2 Read an analog channel -CMD_ANA_GETALL = 101 # 0 8 Read all analog channels - -# MPR121 GPIO constants -GPIO_INPUT = 1 -GPIO_INPUT_PU = 2 -GPIO_INPUT_PD = 3 -GPIO_OUTPUT = 4 -GPIO_OUTPUT_HS = 5 -GPIO_OUTPUT_LS = 6 -GPIO_HIGH = True -GPIO_LOW = False +from spi import SPI +from usb_serial import Serial +from . import analog +from . import capacitive +from . import i2c +from . import neopixel +from . import servo class _Hardware(object): def __init__(self): @@ -83,56 +28,18 @@ def __init__(self): # the hardware class from multiple threads. self.lock = threading.Lock() - # Setup SPI - self.spi = spidev.SpiDev() - self.spi.open(0, 0) - self.spi.mode = 0b00 - - # TODO: Further testing of SPI speeds - # NeoKeypad.lua started showing strange behavior at 500kHz. - # Presumably because neo_show() disables interrupts momentarily, - # Causing the ATmega328 to miss SPI interrupts - # Touch app shows spikes at 250kHz, but not at 122kHz. - - #self.spi.max_speed_hz = 50000 # 50kHz - #self.spi.max_speed_hz = 500000 # 500kHz - #self.spi.max_speed_hz = 250000 # 250kHz - self.spi.max_speed_hz = 122000 # 122kHz + # self.analog = + self.Analog = analog.Analog() + self.Capacitive = capacitive.Capacitive() + self.I2C = i2c.I2C() + self.Neopixel = neopixel.Neopixel() + self.Servo = servo.Servo() + self.SPI = SPI + self.Serial = Serial def __del__(self): pass - def spi_command(self, cmd, params=None, returned=0, delay=0): - """ - Send a command over the SPI bus to the ATmega328. - Optionally reads the result buffer and returns those Bytes. - - :param string cmd: spi command - :param strin params: parameters for the command - :param int returned: size of result reading - :param int delay: delay between sending the command and reading the result - - :return: result buffer (Bytes) - :rtype: list - """ - # Send command - if params: - self.spi.xfer2([cmd] + params) - else: - self.spi.xfer2([cmd]) - - # Delay - if delay: - time.sleep(delay) - - # Read result - if returned: - data = self.spi.xfer2([CMD_READ] + [255 for i in range(returned)]) - # First byte is junk, this is due to the way SPI works - return data[1:] - else: - return - # > GENERAL def ping(self): """ @@ -141,371 +48,19 @@ def ping(self): :return: True if shield is connected :rtype: bool """ - return self.spi_command(CMD_PING, returned=1)[0] == 0xAA + return SPI.command(CMD_PING, returned=1)[0] == 0xAA def reset(self): """Resets the ATmega328, MPR121 and PCA9685.""" - self.spi_command(CMD_RESET, delay=2) + SPI.command(CMD_RESET, delay=2) def led_on(self): """Turns status LED on.""" - self.spi_command(CMD_LEDON) + SPI.command(CMD_LEDON) def led_off(self): """Turns status LED off.""" - self.spi_command(CMD_LEDOFF) - - # > I2C - def i2c_detect(self, addr): - """ - Returns True if an I2C device is found at a particular address. - - :param int addr: address of the I2C device. - - :return: I2C device detected - :rtype: bool - """ - return self.spi_command( - CMD_I2C_DETECT, params=[addr], returned=1)[0] == 1 - - def i2c_read8(self, addr, reg): - """ - Read a Byte from an I2C device. - - :param int addr: address of the I2C device. - :param int reg: register address in the I2C device - - :return: what is the function returning? - :rtype: var - """ - return self.spi_command( - CMD_I2C_READ8, params=[addr, reg], returned=1)[0] - - def i2c_write8(self, addr, reg, data): - """ - Write a Byte to an I2C device. - - :param int addr: address of the I2C device. - :param int reg: register address in the I2C device - :param var data: Byte to send - """ - self.spi_command(CMD_I2C_WRITE8, params=[addr, reg, data]) - - def i2c_read16(self, addr, reg): - """ - Read 2 bytes from an I2C device. - - :param int addr: address of the I2C device. - :param int reg: register address in the I2C device - - :return: 2 Bytes - :rtype: var - """ - data = self.spi_command(CMD_I2C_READ16, params=[addr, reg], returned=2) - return (data[0] << 8) | data[1] - - def i2C_write16(self, addr, reg, data): - """ - Write 2 bytes to an I2C device. - - :param int addr: address of the I2C device. - :param int reg: register address in the I2C device - :param var data: Bytes to send - """ - val1 = (data & 0xFF00) >> 8 - val2 = (data & 0x00FF) - - self.spi_command(CMD_I2C_WRITE16, params=[addr, reg, val1, val2]) - - # > SERVO - def servo_init(self): - """Set up the PCA9685 for driving servos.""" - self.spi_command(CMD_SERVO_INIT, delay=0.02) - - def servo_enable(self): - """Turns on the servo power MOSFET, enabling all servos.""" - self.spi_command(CMD_SERVO_ENABLE) - - def servo_disable(self): - """Turns off the servo power MOSFET, disabling all servos.""" - self.spi_command(CMD_SERVO_DISABLE) - - def servo_neutral(self): - """Set all servos to 1500us.""" - self.spi_command(CMD_SERVO_NEUTRAL, delay=0.008) - - def servo_set(self, channel, pos): - """ - Set the position of one servo. - Pos in us, 500 to 2500 - - :param int channel: channel of the servo - :param int pos: position of the servo (500 to 2500) - """ - offtime = (pos + 2) // 4 - self.spi_command( - CMD_SERVO_SET, - params=[channel, offtime >> 8, offtime & 0x00FF], - delay=0.008) - - def servo_set_all(self, pos_list): - """ - Set position of all 16 servos using a list. - - :param list pos_list: list of servo positions - """ - spi_params = [] - i = 0 - for pos in pos_list: - if pos is None: - # Tell FW not to update this servo - spi_params.append(0xFF) - spi_params.append(0xFF) - else: - offtime = (pos + 2) // 4 - spi_params.append(offtime >> 8) - spi_params.append(offtime & 0x0FF) - i = i + 1 - - self.spi_command(CMD_SERVO_SETALL, params=spi_params, delay=0.008) - - # > CAPACITIVE TOUCH - def cap_init(self, electrodes, gpios=0, autoconfig=True): - """ - Initialize the MPR121 capacitive touch sensor. - - :param int electrodes: amount of electrodes - :param int gpios: amount of gpios - :param bool autoconfig: - """ - ac = 1 if autoconfig else 0 - self.spi_command( - CMD_CAP_INIT, params=[electrodes, gpios, ac], delay=0.05) - - def cap_set_threshold(self, electrode, touch, release): - """ - Set an electrode's touch and release threshold. - - :param int electrode: index of electrode - :param int touch: threshold value for touch detection - :param int release: threshold value for release detection - """ - self.spi_command(CMD_CAP_SETTH, params=[electrode, touch, release]) - - def cap_get_filtered_data(self): - """ - Get list of electrode filtered data (10 bits per electrode). - - :return: electrode filtered data (10 bits per electrode). - :rtype: list - """ - data = [] - ret = Hardware.spi_command(CMD_CAP_GETFD, returned=24) - for i in range(12): - data.append(ret[i * 2] + (ret[i * 2 + 1] << 8)) - return data - - def cap_get_baseline_data(self): - """ - Get list of electrode baseline data. - Result is 10 bits, but the 2 least significant bits are set to 0. - - :return: electrode baseline data (10 bits). - :rtype: list - """ - data = Hardware.spi_command(CMD_CAP_GETBD, returned=12) - # High 8 bits of 10 are returned. - # Shift 2 so it's the same order of magnitude as cap_get_filtered_data(). - data = map(lambda x: x << 2, data) - return data - - def cap_get_touched(self): - """ - Returns the values of the touch registers, - each bit corresponds to one electrode. - - :return: values of the touch registers, - :rtype: list - """ - data = self.spi_command(CMD_CAP_TOUCHED, returned=2) - return (data[0] << 8) | data[1] - - def cap_set_gpio_pinmode(self, gpio, pinmode): - """ - Sets a GPIO channel's pin mode. - - :param int gpio: gpio channel - :param int pinmode: pinmode to set - """ - bitmask = 1 << gpio - self.spi_command(CMD_CAP_SETGPIO, params=[bitmask, pinmode]) - - def cap_read_gpio(self): - """ - Returns the status of all GPIO channels, - each bit corresponds to one gpio channel. - - :return: status of all GPIO channels. - :rtype: list - """ - # TODO: Add optional pin parameter - return self.spi_command(CMD_CAP_GPIOREAD) - - def cap_write_gpio(self, gpio, data): - """ - Set GPIO channel value. - - :param int gpio: gpio channel - :param int data: data to write to gpio channel. - """ - bitmask = 1 << gpio - setclr = 1 if data else 0 - self.spi_command(CMD_CAP_GPIOWRITE, params=[bitmask, setclr]) - - # > NEOPIXEL - def neo_init(self, num_leds): - """ - Initialize the NeoPixel library. - - :param int num_leds: number of neopixel leds. - """ - self.spi_command(CMD_NEO_INIT, params=[num_leds]) - - def neo_enable(self): - """ - Turns on the NeoPixel MOSFET, enabling the NeoPixels. - Data is lost when pixels are disabled, so call neo_show() again afterwards. - """ - self.spi_command(CMD_NEO_ENABLE) - - def neo_disable(self): - """ - Turns off the NeoPixel MOSFET, disabling the NeoPixels. - Data is lost when pixels are disabled. - """ - self.spi_command(CMD_NEO_DISABLE) - - def neo_set_brightness(self, brightness): - """ - Set the NeoPixel's global brightness, 0-255. - - :param int brightness: brightness to set (0-255) - """ - self.spi_command(CMD_NEO_SETBRIGHT, params=[brightness]) - - def neo_show(self): - """Sends the pixel data from the ATmega328 to the NeoPixels.""" - self.spi_command(CMD_NEO_SHOW) - - def neo_set_pixel(self, pixel, r, g, b): - """ - Set the color of a single pixel. - - :param int pixel: pixel index - :param int r: red color value (0-255) - :param int g: green color value (0-255) - :param int b: blue color value (0-255) - """ - self.spi_command(CMD_NEO_SET, params=[pixel, r, g, b]) - - def neo_set_range(self, start, end, r, g, b): - """ - Set the color of a range of pixels. - - :param int start: start index of led range - :param int end: end index of led range - :param int r: red color value (0-255) - :param int g: green color value (0-255) - :param int b: blue color value (0-255) - """ - self.spi_command(CMD_NEO_SETRANGE, params=[start, end, r, g, b]) - - def neo_set_all(self, r, g, b): - """ - Set the color of the entire strip. - - :param int r: red color value (0-255) - :param int g: green color value (0-255) - :param int b: blue color value (0-255) - """ - self.spi_command(CMD_NEO_SETALL, params=[r, g, b]) - - def neo_set_pixel_hsv(self, pixel, h, s, v): - """ - Set the HSV color of a single pixel. - - :param int pixel: pixel index - :param int h: hue color value (0-255) - :param int s: saturation color value (0-255) - :param int v: value color value (0-255) - """ - self.spi_command(CMD_NEO_SETHSV, params=[pixel, h, s, v]) - - def neo_set_range_hsv(self, start, end, h, s, v): - """ - Set the HSV color of a range of pixels. - - :param int start: start index of led range - :param int end: end index of led range - :param int h: hue color value (0-255) - :param int s: saturation color value (0-255) - :param int v: value color value (0-255) - """ - self.spi_command(CMD_NEO_SETRANGEHSV, params=[start, end, h, s, v]) - - def neo_set_all_hsv(self, h, s, v): - """ - Set the HSV color of the entire strip. - - :param int h: hue color value (0-255) - :param int s: saturation color value (0-255) - :param int v: value color value (0-255) - """ - self.spi_command(CMD_NEO_SETALLHSV, params=[h, s, v]) - - # > ANALOG - def ana_read_channel(self, channel): - """ - Reads the value of a single analog channel. - - :param int channel: analog channel to read - - :return: analog value of the channel - :rtype: var - """ - data = self.spi_command(CMD_ANA_GET, params=[channel], returned=2) - return data[0] << 8 | data[1] - - def ana_read_all_channels(self): - """ - Reads all analog channels and returns them as a list. - - :return: analog values - :rtype: list - """ - data = self.spi_command(CMD_ANA_GETALL, returned=2) - return [ - data[0] << 8 | data[1], data[2] << 8 | data[3], data[4] << 8 | - data[5], data[6] << 8 | data[7] - ] - - # Methods for backward compatibility - servo_power_on = servo_enable - servo_power_off = servo_disable - set_servo_us = servo_set - - def set_all_servo_us(self, us): - """ - Set all servos to a certain position (us) - - :param int us: position in us - """ - if us == 1500: - self.servo_neutral() - else: - pos_list = [us for i in range(16)] - self.servo_set_all(pos_list) + SPI.command(CMD_LEDOFF) # Global instance that can be accessed by apps and scripts Hardware = _Hardware() -Hardware.spi_command(CMD_RESET) diff --git a/src/opsoro/hardware/analog.py b/src/opsoro/hardware/analog.py new file mode 100644 index 0000000..e8263ab --- /dev/null +++ b/src/opsoro/hardware/analog.py @@ -0,0 +1,33 @@ +from opsoro.hardware.spi import SPI + + +# > ANALOG IN OUT +CMD_ANA_GET = 100 # 1 2 Read an analog channel +CMD_ANA_GETALL = 101 # 0 8 Read all analog channels + +class Analog(object): + # > ANALOG + def read_channel(self, channel): + """ + Reads the value of a single analog channel. + + :param int channel: analog channel to read + + :return: analog value of the channel + :rtype: var + """ + data = SPI.command(CMD_ANA_GET, params=[channel], returned=2) + return data[0] << 8 | data[1] + + def read_all_channels(self): + """ + Reads all analog channels and returns them as a list. + + :return: analog values + :rtype: list + """ + data = SPI.command(CMD_ANA_GETALL, returned=2) + return [ + data[0] << 8 | data[1], data[2] << 8 | data[3], data[4] << 8 | + data[5], data[6] << 8 | data[7] + ] diff --git a/src/opsoro/hardware/capacitive.py b/src/opsoro/hardware/capacitive.py new file mode 100644 index 0000000..d9bd213 --- /dev/null +++ b/src/opsoro/hardware/capacitive.py @@ -0,0 +1,115 @@ +from opsoro.hardware.spi import SPI + +# > CAPACITIVE TOUCH IN OUT +CMD_CAP_INIT = 60 # 3 0 Init MPR121 +CMD_CAP_SETTH = 61 # 3 0 Set pin touch/release threshold +CMD_CAP_GETFD = 62 # 0 24 Get pin filtered data (10 bits per electrode) +CMD_CAP_GETBD = 63 # 1 1 Get pin baseline data, high 8 bits of 10 +CMD_CAP_TOUCHED = 64 # 0 2 Get touched status +CMD_CAP_SETGPIO = 65 # 2 0 Set GPIO mode +CMD_CAP_GPIOREAD = 66 # 0 1 Read GPIO pin +CMD_CAP_GPIOWRITE = 67 # 2 0 Write GPIO pin + + +# MPR121 GPIO constants +GPIO_INPUT = 1 +GPIO_INPUT_PU = 2 +GPIO_INPUT_PD = 3 +GPIO_OUTPUT = 4 +GPIO_OUTPUT_HS = 5 +GPIO_OUTPUT_LS = 6 +GPIO_HIGH = True +GPIO_LOW = False + +class Capacitive(object): + # > CAPACITIVE TOUCH + def init(self, electrodes, gpios=0, autoconfig=True): + """ + Initialize the MPR121 capacitive touch sensor. + + :param int electrodes: amount of electrodes + :param int gpios: amount of gpios + :param bool autoconfig: + """ + ac = 1 if autoconfig else 0 + SPI.command(CMD_CAP_INIT, params=[electrodes, gpios, ac], delay=0.05) + + def set_threshold(self, electrode, touch, release): + """ + Set an electrode's touch and release threshold. + + :param int electrode: index of electrode + :param int touch: threshold value for touch detection + :param int release: threshold value for release detection + """ + SPI.command(CMD_CAP_SETTH, params=[electrode, touch, release]) + + def get_filtered_data(self): + """ + Get list of electrode filtered data (10 bits per electrode). + + :return: electrode filtered data (10 bits per electrode). + :rtype: list + """ + data = [] + ret = SPI.command(CMD_CAP_GETFD, returned=24) + for i in range(12): + data.append(ret[i * 2] + (ret[i * 2 + 1] << 8)) + return data + + def get_baseline_data(self): + """ + Get list of electrode baseline data. + Result is 10 bits, but the 2 least significant bits are set to 0. + + :return: electrode baseline data (10 bits). + :rtype: list + """ + data = SPI.command(CMD_CAP_GETBD, returned=12) + # High 8 bits of 10 are returned. + # Shift 2 so it's the same order of magnitude as cap_get_filtered_data(). + data = map(lambda x: x << 2, data) + return data + + def get_touched(self): + """ + Returns the values of the touch registers, + each bit corresponds to one electrode. + + :return: values of the touch registers, + :rtype: list + """ + data = SPI.command(CMD_CAP_TOUCHED, returned=2) + return (data[0] << 8) | data[1] + + def set_gpio_pinmode(self, gpio, pinmode): + """ + Sets a GPIO channel's pin mode. + + :param int gpio: gpio channel + :param int pinmode: pinmode to set + """ + bitmask = 1 << gpio + SPI.command(CMD_CAP_SETGPIO, params=[bitmask, pinmode]) + + def read_gpio(self): + """ + Returns the status of all GPIO channels, + each bit corresponds to one gpio channel. + + :return: status of all GPIO channels. + :rtype: list + """ + # TODO: Add optional pin parameter + return SPI.command(CMD_CAP_GPIOREAD) + + def write_gpio(self, gpio, data): + """ + Set GPIO channel value. + + :param int gpio: gpio channel + :param int data: data to write to gpio channel. + """ + bitmask = 1 << gpio + setclr = 1 if data else 0 + SPI.command(CMD_CAP_GPIOWRITE, params=[bitmask, setclr]) diff --git a/src/opsoro/hardware/dummy_spidev.py b/src/opsoro/hardware/dummy_spidev.py new file mode 100644 index 0000000..9a76148 --- /dev/null +++ b/src/opsoro/hardware/dummy_spidev.py @@ -0,0 +1,15 @@ +from opsoro.console_msg import print_spi + +class SpiDev(object): + def __init__(self): + self.mode = None + self.max_speed_hz = 0 + print_spi('No SPI installed, using dummy class') + + def open(self,*args): + # print_spi('open: {}'.format(args)) + pass + + def xfer2(self,*args): + # print_spi('transfer: {}'.format(args)) + pass diff --git a/src/opsoro/hardware/i2c.py b/src/opsoro/hardware/i2c.py index 4e05e4a..92d88d3 100644 --- a/src/opsoro/hardware/i2c.py +++ b/src/opsoro/hardware/i2c.py @@ -1,161 +1,70 @@ -#!/usr/bin/python -import re -import smbus +from opsoro.hardware.spi import SPI -# =========================================================================== -# I2C Class -# =========================================================================== +# > I2C IN OUT +CMD_I2C_DETECT = 20 # 1 1 Test if there's a device at addr +CMD_I2C_READ8 = 21 # 2 1 Read byte +CMD_I2C_WRITE8 = 22 # 3 0 Write byte +CMD_I2C_READ16 = 23 # 2 2 Read 2 bytes +CMD_I2C_WRITE16 = 24 # 4 0 Write 2 bytes -class I2C(object): - @staticmethod - def getPiRevision(): - "Gets the version number of the Raspberry Pi board" - # Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History - try: - with open('/proc/cpuinfo', 'r') as infile: - for line in infile: - # Match a line of the form "Revision : 0002" while ignoring extra - # info in front of the revsion (like 1000 when the Pi was over-volted). - match = re.match('Revision\s+:\s+.*(\w{4})$', line) - if match and match.group(1) in ['0000', '0002', '0003']: - # Return revision 1 if revision ends with 0000, 0002 or 0003. - return 1 - elif match: - # Assume revision 2 if revision ends with any other 4 chars. - return 2 - # Couldn't find the revision, assume revision 0 like older code for compatibility. - return 0 - except: - return 0 - - @staticmethod - def getPiI2CBusNumber(): - # Gets the I2C bus number /dev/i2c# - return 1 if I2C.getPiRevision() > 1 else 0 - - def __init__(self, address, busnum=-1, debug=False): - self.address = address - # By default, the correct I2C bus is auto-detected using /proc/cpuinfo - # Alternatively, you can hard-code the bus version below: - # self.bus = smbus.SMBus(0); # Force I2C0 (early 256MB Pi's) - # self.bus = smbus.SMBus(1); # Force I2C1 (512MB Pi's) - self.bus = smbus.SMBus(busnum if busnum >= 0 else I2C.getPiI2CBusNumber()) - self.debug = debug - - def reverseByteOrder(self, data): - "Reverses the byte order of an int (16-bit) or long (32-bit) value" - # Courtesy Vishal Sapre - byteCount = len(hex(data)[2:].replace('L','')[::2]) - val = 0 - for i in range(byteCount): - val = (val << 8) | (data & 0xff) - data >>= 8 - return val - - def errMsg(self): - #print "Error accessing 0x%02X: Check your I2C address" % self.address - return -1 - - def write8(self, reg, value): - "Writes an 8-bit value to the specified register/address" - try: - self.bus.write_byte_data(self.address, reg, value) - if self.debug: - print "I2C: Wrote 0x%02X to register 0x%02X" % (value, reg) - except IOError, err: - return self.errMsg() - - def write16(self, reg, value): - "Writes a 16-bit value to the specified register/address pair" - try: - self.bus.write_word_data(self.address, reg, value) - if self.debug: - print ("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" % - (value, reg, reg+1)) - except IOError, err: - return self.errMsg() - - def writeRaw8(self, value): - "Writes an 8-bit value on the bus" - try: - self.bus.write_byte(self.address, value) - if self.debug: - print "I2C: Wrote 0x%02X" % value - except IOError, err: - return self.errMsg() - - def writeList(self, reg, list): - "Writes an array of bytes using I2C format" - try: - if self.debug: - print "I2C: Writing list to register 0x%02X:" % reg - print list - self.bus.write_i2c_block_data(self.address, reg, list) - except IOError, err: - return self.errMsg() - - def readList(self, reg, length): - "Read a list of bytes from the I2C device" - try: - results = self.bus.read_i2c_block_data(self.address, reg, length) - if self.debug: - print ("I2C: Device 0x%02X returned the following from reg 0x%02X" % - (self.address, reg)) - print results - return results - except IOError, err: - return self.errMsg() - - def readU8(self, reg): - "Read an unsigned byte from the I2C device" - try: - result = self.bus.read_byte_data(self.address, reg) - if self.debug: - print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % - (self.address, result & 0xFF, reg)) - return result - except IOError, err: - return self.errMsg() - - def readS8(self, reg): - "Reads a signed byte from the I2C device" - try: - result = self.bus.read_byte_data(self.address, reg) - if result > 127: result -= 256 - if self.debug: - print ("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % - (self.address, result & 0xFF, reg)) - return result - except IOError, err: - return self.errMsg() - - def readU16(self, reg, little_endian=True): - "Reads an unsigned 16-bit value from the I2C device" - try: - result = self.bus.read_word_data(self.address,reg) - # Swap bytes if using big endian because read_word_data assumes little - # endian on ARM (little endian) systems. - if not little_endian: - result = ((result << 8) & 0xFF00) + (result >> 8) - if (self.debug): - print "I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg) - return result - except IOError, err: - return self.errMsg() - - def readS16(self, reg, little_endian=True): - "Reads a signed 16-bit value from the I2C device" - try: - result = self.readU16(reg,little_endian) - if result > 32767: result -= 65536 - return result - except IOError, err: - return self.errMsg() - -if __name__ == '__main__': - try: - bus = I2C(address=0) - print "Default I2C bus is accessible" - except: - print "Error accessing default I2C bus" +class I2C(object): + # > I2C + def detect(self, addr): + """ + Returns True if an I2C device is found at a particular address. + + :param int addr: address of the I2C device. + + :return: I2C device detected + :rtype: bool + """ + return SPI.command(CMD_I2C_DETECT, params=[addr], returned=1)[0] == 1 + + def read8(self, addr, reg): + """ + Read a Byte from an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + + :return: what is the function returning? + :rtype: var + """ + return SPI.command(CMD_I2C_READ8, params=[addr, reg], returned=1)[0] + + def write8(self, addr, reg, data): + """ + Write a Byte to an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + :param var data: Byte to send + """ + SPI.command(CMD_I2C_WRITE8, params=[addr, reg, data]) + + def read16(self, addr, reg): + """ + Read 2 bytes from an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + + :return: 2 Bytes + :rtype: var + """ + data = SPI.command(CMD_I2C_READ16, params=[addr, reg], returned=2) + return (data[0] << 8) | data[1] + + def write16(self, addr, reg, data): + """ + Write 2 bytes to an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + :param var data: Bytes to send + """ + val1 = (data & 0xFF00) >> 8 + val2 = (data & 0x00FF) + + SPI.command(CMD_I2C_WRITE16, params=[addr, reg, val1, val2]) diff --git a/src/opsoro/hardware/neopixel.py b/src/opsoro/hardware/neopixel.py new file mode 100644 index 0000000..7d2fcca --- /dev/null +++ b/src/opsoro/hardware/neopixel.py @@ -0,0 +1,118 @@ +from opsoro.hardware.spi import SPI + + +# > NEOPIXEL IN OUT +CMD_NEO_INIT = 80 # 1 0 Init Neopixel +CMD_NEO_ENABLE = 81 # 0 0 Turn on MOSFET +CMD_NEO_DISABLE = 82 # 0 0 Turn off MOSFET +CMD_NEO_SETBRIGHT = 83 # 1 0 Set brightness +CMD_NEO_SHOW = 84 # 0 0 Show pixels +CMD_NEO_SET = 85 # 4 0 Set single pixel +CMD_NEO_SETRANGE = 86 # 5 0 Set range of pixels +CMD_NEO_SETALL = 87 # 3 0 Set all pixels +CMD_NEO_SETHSV = 88 # 4 0 Set single pixel HSV +CMD_NEO_SETRANGEHSV = 89 # 5 0 Set range of pixels HSV +CMD_NEO_SETALLHSV = 90 # 3 0 Set all pixels HSV + + +class Neopixel(object): + # > NEOPIXEL + def init(self, num_leds): + """ + Initialize the NeoPixel library. + + :param int num_leds: number of neopixel leds. + """ + SPI.command(CMD_NEO_INIT, params=[num_leds]) + + def enable(self): + """ + Turns on the NeoPixel MOSFET, enabling the NeoPixels. + Data is lost when pixels are disabled, so call show() again afterwards. + """ + SPI.command(CMD_NEO_ENABLE) + + def disable(self): + """ + Turns off the NeoPixel MOSFET, disabling the NeoPixels. + Data is lost when pixels are disabled. + """ + SPI.command(CMD_NEO_DISABLE) + + def set_brightness(self, brightness): + """ + Set the NeoPixel's global brightness, 0-255. + + :param int brightness: brightness to set (0-255) + """ + SPI.command(CMD_NEO_SETBRIGHT, params=[brightness]) + + def show(self): + """Sends the pixel data from the ATmega328 to the NeoPixels.""" + SPI.command(CMD_NEO_SHOW) + + def set_pixel(self, pixel, r, g, b): + """ + Set the color of a single pixel. + + :param int pixel: pixel index + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + SPI.command(CMD_NEO_SET, params=[pixel, r, g, b]) + + def set_range(self, start, end, r, g, b): + """ + Set the color of a range of pixels. + + :param int start: start index of led range + :param int end: end index of led range + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + SPI.command(CMD_NEO_SETRANGE, params=[start, end, r, g, b]) + + def set_all(self, r, g, b): + """ + Set the color of the entire strip. + + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + SPI.command(CMD_NEO_SETALL, params=[r, g, b]) + + def set_pixel_hsv(self, pixel, h, s, v): + """ + Set the HSV color of a single pixel. + + :param int pixel: pixel index + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + SPI.command(CMD_NEO_SETHSV, params=[pixel, h, s, v]) + + def set_range_hsv(self, start, end, h, s, v): + """ + Set the HSV color of a range of pixels. + + :param int start: start index of led range + :param int end: end index of led range + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + SPI.command(CMD_NEO_SETRANGEHSV, params=[start, end, h, s, v]) + + def set_all_hsv(self, h, s, v): + """ + Set the HSV color of the entire strip. + + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + SPI.command(CMD_NEO_SETALLHSV, params=[h, s, v]) diff --git a/src/opsoro/hardware/servo.py b/src/opsoro/hardware/servo.py new file mode 100644 index 0000000..cbd7553 --- /dev/null +++ b/src/opsoro/hardware/servo.py @@ -0,0 +1,75 @@ +from opsoro.hardware.spi import SPI + + +# > SERVO IN OUT +CMD_SERVO_INIT = 40 # 0 0 Init PCA9685 +CMD_SERVO_ENABLE = 41 # 0 0 Turn on MOSFET +CMD_SERVO_DISABLE = 42 # 0 0 Turn off MOSFET +CMD_SERVO_NEUTRAL = 43 # 0 0 Set all servos to 1500 +CMD_SERVO_SET = 44 # 3 0 Set 1 servo position +CMD_SERVO_SETALL = 45 # 32 0 Set position of all servos + + +class Servo(object): + # > SERVO + def init(self): + """Set up the PCA9685 for driving servos.""" + SPI.command(CMD_SERVO_INIT, delay=0.02) + + def enable(self): + """Turns on the servo power MOSFET, enabling all servos.""" + SPI.command(CMD_SERVO_ENABLE) + + def disable(self): + """Turns off the servo power MOSFET, disabling all servos.""" + SPI.command(CMD_SERVO_DISABLE) + + def neutral(self): + """Set all servos to 1500us.""" + SPI.command(CMD_SERVO_NEUTRAL, delay=0.008) + + def set(self, channel, pos): + """ + Set the position of one servo. + Pos in us, 500 to 2500 + + :param int channel: channel of the servo + :param int pos: position of the servo (500 to 2500) + """ + offtime = (pos + 2) // 4 + SPI.command(CMD_SERVO_SET, + params=[channel, offtime >> 8, offtime & 0x00FF], + delay=0.008) + + def set_all_us(self, us): + """ + Set all servos to a certain position (us) + + :param int us: position in us + """ + if us == 1500: + neutral() + else: + pos_list = [us for i in range(16)] + self.set_all(pos_list) + + def set_all(self, pos_list): + """ + Set position of all 16 servos using a list. + + :param list pos_list: list of servo positions + """ + spi_params = [] + i = 0 + for pos in pos_list: + if pos is None: + # Tell FW not to update this servo + spi_params.append(0xFF) + spi_params.append(0xFF) + else: + offtime = (pos + 2) // 4 + spi_params.append(offtime >> 8) + spi_params.append(offtime & 0x0FF) + i = i + 1 + + SPI.command(CMD_SERVO_SETALL, params=spi_params, delay=0.008) diff --git a/src/opsoro/hardware/spi.py b/src/opsoro/hardware/spi.py new file mode 100644 index 0000000..051b661 --- /dev/null +++ b/src/opsoro/hardware/spi.py @@ -0,0 +1,66 @@ +# SPI COMMANDS + +CMD_READ = 2 # 0 ? Return result from previous command +CMD_RESET = 3 # 0 0 Reset the ATmega328 + +import time +try: + import spidev +except ImportError: + import dummy_spidev as spidev + +class _SPI(object): + def __init__(self): + """ + SPI class, used to communicate with the shield. + """ + # Setup SPI + self.spi = spidev.SpiDev() + self.spi.open(0, 0) + self.spi.mode = 0b00 + + # TODO: Further testing of SPI speeds + # NeoKeypad.lua started showing strange behavior at 500kHz. + # Presumably because neo_show() disables interrupts momentarily, + # Causing the ATmega328 to miss SPI interrupts + # Touch app shows spikes at 250kHz, but not at 122kHz. + + #self.spi.max_speed_hz = 50000 # 50kHz + #self.spi.max_speed_hz = 500000 # 500kHz + #self.spi.max_speed_hz = 250000 # 250kHz + self.spi.max_speed_hz = 122000 # 122kHz + + def command(self, cmd, params=None, returned=0, delay=0): + """ + Send a command over the SPI bus to the ATmega328. + Optionally reads the result buffer and returns those Bytes. + + :param string cmd: spi command + :param strin params: parameters for the command + :param int returned: size of result reading + :param int delay: delay between sending the command and reading the result + + :return: result buffer (Bytes) + :rtype: list + """ + # Send command + if params: + self.spi.xfer2([cmd] + params) + else: + self.spi.xfer2([cmd]) + + # Delay + if delay: + time.sleep(delay) + + # Read result + if returned: + data = self.spi.xfer2([CMD_READ] + [255 for i in range(returned)]) + # First byte is junk, this is due to the way SPI works + return data[1:] + else: + return + + +SPI = _SPI() +SPI.command(CMD_RESET) diff --git a/src/opsoro/hardware/test_hardware.py b/src/opsoro/hardware/test_hardware.py new file mode 100644 index 0000000..d39ef73 --- /dev/null +++ b/src/opsoro/hardware/test_hardware.py @@ -0,0 +1,358 @@ +class Dummy_Hardware(object): + def __init__(self): + """ + Hardware class, used to communicate with the shield. + """ + pass + + def __del__(self): + pass + + def spi_command(self, cmd, params=None, returned=0, delay=0): + """ + Send a command over the SPI bus to the ATmega328. + Optionally reads the result buffer and returns those Bytes. + + :param string cmd: spi command + :param strin params: parameters for the command + :param int returned: size of result reading + :param int delay: delay between sending the command and reading the result + + :return: result buffer (Bytes) + :rtype: list + """ + return [] + + # > GENERAL + def ping(self): + """ + Returns True if OPSOROHAT rev3 is connected. + + :return: True if shield is connected + :rtype: bool + """ + return True + + def reset(self): + """Resets the ATmega328, MPR121 and PCA9685.""" + pass + + def led_on(self): + """Turns status LED on.""" + pass + + def led_off(self): + """Turns status LED off.""" + pass + + # > I2C + def i2c_detect(self, addr): + """ + Returns True if an I2C device is found at a particular address. + + :param int addr: address of the I2C device. + + :return: I2C device detected + :rtype: bool + """ + return True + + def i2c_read8(self, addr, reg): + """ + Read a Byte from an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + + :return: what is the function returning? + :rtype: var + """ + return 0 + + def i2c_write8(self, addr, reg, data): + """ + Write a Byte to an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + :param var data: Byte to send + """ + pass + + def i2c_read16(self, addr, reg): + """ + Read 2 bytes from an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + + :return: 2 Bytes + :rtype: var + """ + + return 0 + + def i2C_write16(self, addr, reg, data): + """ + Write 2 bytes to an I2C device. + + :param int addr: address of the I2C device. + :param int reg: register address in the I2C device + :param var data: Bytes to send + """ + pass + + # > SERVO + def servo_init(self): + """Set up the PCA9685 for driving servos.""" + pass + + def servo_enable(self): + """Turns on the servo power MOSFET, enabling all servos.""" + pass + + def servo_disable(self): + """Turns off the servo power MOSFET, disabling all servos.""" + pass + + def servo_neutral(self): + """Set all servos to 1500us.""" + pass + + def servo_set(self, channel, pos): + """ + Set the position of one servo. + Pos in us, 500 to 2500 + + :param int channel: channel of the servo + :param int pos: position of the servo (500 to 2500) + """ + pass + + def servo_set_all(self, pos_list): + """ + Set position of all 16 servos using a list. + + :param list pos_list: list of servo positions + """ + pass + + # > CAPACITIVE TOUCH + def cap_init(self, electrodes, gpios=0, autoconfig=True): + """ + Initialize the MPR121 capacitive touch sensor. + + :param int electrodes: amount of electrodes + :param int gpios: amount of gpios + :param bool autoconfig: + """ + pass + + def cap_set_threshold(self, electrode, touch, release): + """ + Set an electrode's touch and release threshold. + + :param int electrode: index of electrode + :param int touch: threshold value for touch detection + :param int release: threshold value for release detection + """ + pass + + def cap_get_filtered_data(self): + """ + Get list of electrode filtered data (10 bits per electrode). + + :return: electrode filtered data (10 bits per electrode). + :rtype: list + """ + return [] + + def cap_get_baseline_data(self): + """ + Get list of electrode baseline data. + Result is 10 bits, but the 2 least significant bits are set to 0. + + :return: electrode baseline data (10 bits). + :rtype: list + """ + return [] + + def cap_get_touched(self): + """ + Returns the values of the touch registers, + each bit corresponds to one electrode. + + :return: values of the touch registers, + :rtype: list + """ + return [] + + def cap_set_gpio_pinmode(self, gpio, pinmode): + """ + Sets a GPIO channel's pin mode. + + :param int gpio: gpio channel + :param int pinmode: pinmode to set + """ + pass + + def cap_read_gpio(self): + """ + Returns the status of all GPIO channels, + each bit corresponds to one gpio channel. + + :return: status of all GPIO channels. + :rtype: list + """ + return [] + + def cap_write_gpio(self, gpio, data): + """ + Set GPIO channel value. + + :param int gpio: gpio channel + :param int data: data to write to gpio channel. + """ + pass + + # > NEOPIXEL + def neo_init(self, num_leds): + """ + Initialize the NeoPixel library. + + :param int num_leds: number of neopixel leds. + """ + pass + + def neo_enable(self): + """ + Turns on the NeoPixel MOSFET, enabling the NeoPixels. + Data is lost when pixels are disabled, so call neo_show() again afterwards. + """ + pass + + def neo_disable(self): + """ + Turns off the NeoPixel MOSFET, disabling the NeoPixels. + Data is lost when pixels are disabled. + """ + pass + + def neo_set_brightness(self, brightness): + """ + Set the NeoPixel's global brightness, 0-255. + + :param int brightness: brightness to set (0-255) + """ + pass + + def neo_show(self): + """Sends the pixel data from the ATmega328 to the NeoPixels.""" + pass + + def neo_set_pixel(self, pixel, r, g, b): + """ + Set the color of a single pixel. + + :param int pixel: pixel index + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + pass + + def neo_set_range(self, start, end, r, g, b): + """ + Set the color of a range of pixels. + + :param int start: start index of led range + :param int end: end index of led range + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + pass + + def neo_set_all(self, r, g, b): + """ + Set the color of the entire strip. + + :param int r: red color value (0-255) + :param int g: green color value (0-255) + :param int b: blue color value (0-255) + """ + pass + + def neo_set_pixel_hsv(self, pixel, h, s, v): + """ + Set the HSV color of a single pixel. + + :param int pixel: pixel index + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + pass + + def neo_set_range_hsv(self, start, end, h, s, v): + """ + Set the HSV color of a range of pixels. + + :param int start: start index of led range + :param int end: end index of led range + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + pass + + def neo_set_all_hsv(self, h, s, v): + """ + Set the HSV color of the entire strip. + + :param int h: hue color value (0-255) + :param int s: saturation color value (0-255) + :param int v: value color value (0-255) + """ + pass + + # > ANALOG + def ana_read_channel(self, channel): + """ + Reads the value of a single analog channel. + + :param int channel: analog channel to read + + :return: analog value of the channel + :rtype: var + """ + return 0 + + def ana_read_all_channels(self): + """ + Reads all analog channels and returns them as a list. + + :return: analog values + :rtype: list + """ + return [] + + # Methods for backward compatibility + # servo_power_on = servo_enable + # servo_power_off = servo_disable + # set_servo_us = servo_set + + def set_all_servo_us(self, us): + """ + Set all servos to a certain position (us) + + :param int us: position in us + """ + if us == 1500: + self.servo_neutral() + else: + pos_list = [us for i in range(16)] + self.servo_set_all(pos_list) + +# Global instance that can be accessed by apps and scripts +Hardware = Dummy_Hardware() diff --git a/src/opsoro/hardware/usb_serial.py b/src/opsoro/hardware/usb_serial.py new file mode 100644 index 0000000..a4c6ab4 --- /dev/null +++ b/src/opsoro/hardware/usb_serial.py @@ -0,0 +1,43 @@ +import serial as pyserial +import glob + +from opsoro.console_msg import * + +class _Serial(object): + # > SERIAL + def __init__(self): + """Initialize serial.""" + self.ports = [] + self.port = None + self.scan() + + def scan(self): + visible_ports = glob.glob('/dev/ttyACM[0-9]*') + self.ports = [] + for port in visible_ports: + try: + print_info(port) + s = pyserial.Serial(port) + s.close() + self.ports.append(port) + except Exception as e: + print e + pass + print_info(self.ports) + + # def connect(self, port, baudrate): + # self.port = pyserial.Serial("/dev/ttyACM0", baudrate = 9600, timeout = 2) + # pass + + # def readline(self): + # pass + + def send(self, text, port_id=0, baudrate=9600): + try: + s = pyserial.Serial(self.ports[port_id], baudrate) + s.write(text) + s.close() + except Exception as e: + print_error('Error sending serial command.') + +Serial = _Serial() diff --git a/src/opsoro/play.py b/src/opsoro/play.py new file mode 100644 index 0000000..9cc4c2d --- /dev/null +++ b/src/opsoro/play.py @@ -0,0 +1,57 @@ +import urllib +import requests + + +from opsoro.console_msg import * + +# PLAY_URL = 'https://robot.opsoro.be/' +PLAY_URL = 'https://opsoro.a2hosted.com/' + +class _Play(object): + def __init__(self): + self.uuid = None + self.token = None + self.username = None + self.password = None + pass + + def is_online(self): + try : + data = urllib.urlopen(PLAY_URL) + return True + except Exception as e: + return False + + def login(self, username = None, password = None): + if username is not None: + self.username = username + if password is not None: + self.password = password + + if not self.is_online(): + return False + + url_login = PLAY_URL + 'accounts/login/' + url_run = PLAY_URL + 'robot/token/' + + # # Use 'with' to ensure the session context is closed after use. + with requests.Session() as s: + s.get(url_login) + csrftoken = s.cookies['csrftoken'] + payload = { + 'username': self.username, + 'password': self.password, + 'csrfmiddlewaretoken':csrftoken, + 'next': url_run + } + p = s.post(url_login, data=payload, headers=dict(Referer=url_login)) + returns = p.text.split('\n') + if len(returns) == 2: + self.uuid = returns[0] + self.token = returns[1] + return True + else: + print_error('Unable to parse play.opsoro uuid and token') + return False + +Play = _Play() diff --git a/src/opsoro/robot.py b/src/opsoro/robot.py index f023a7e..0a70cfe 100644 --- a/src/opsoro/robot.py +++ b/src/opsoro/robot.py @@ -11,9 +11,13 @@ from opsoro.console_msg import * from opsoro.stoppable_thread import StoppableThread from opsoro.hardware import Hardware +# import opsoro.hardware as hardware +# from opsoro.Hardware.Servo import Hardware + from opsoro.preferences import Preferences from functools import partial +from enum import IntEnum import os import time @@ -32,8 +36,18 @@ MODULES = {'eye': Eye, 'eyebrow': Eyebrow, 'mouth': Mouth} - class _Robot(object): + class Activation(IntEnum): + MANUAL = 0 # 0: Manual start/stop + AUTO = 1 # 1: Start robot automatically (alive feature according to preferences) + AUTO_ALIVE = 2 # 2: Start robot automatically and enable alive feature + AUTO_NOT_ALIVE = 3 # 3: Start robot automatically and disable alive feature + + class Connection(IntEnum): + OFFLINE = 0 # 0: No online capability + PARTLY = 1 # 1: Needs online for extras, but works without + ONLINE = 2 # 2: Requires to be online to work + def __init__(self): self.modules = {} self._config = {} @@ -51,7 +65,7 @@ def __init__(self): def start(self): print_info('Start Robot loop') with Hardware.lock: - Hardware.servo_init() + Hardware.Servo.init() self.start_update_loop() if Preferences.get('alive', 'enabled', False): @@ -62,7 +76,7 @@ def start_update_loop(self): self._dof_t.stop() with Hardware.lock: - Hardware.servo_enable() + Hardware.Servo.enable() self._dof_t = StoppableThread(target=self.dof_update_loop) @@ -72,7 +86,7 @@ def stop_update_loop(self): if self.auto_enable_servos: with Hardware.lock: - Hardware.servo_disable() + Hardware.Servo.disable() def start_alive_loop(self): if self._alive_t is not None: @@ -87,7 +101,7 @@ def stop(self): print_info('Stop Robot loop') with Hardware.lock: - Hardware.servo_disable() + Hardware.Servo.disable() self.stop_alive_loop() self.stop_update_loop() diff --git a/src/opsoro/server/__init__.py b/src/opsoro/server/__init__.py index e9cf653..c09a651 100644 --- a/src/opsoro/server/__init__.py +++ b/src/opsoro/server/__init__.py @@ -1,9 +1,10 @@ from flask import Flask, request, render_template, redirect, url_for, flash, session, jsonify, send_from_directory from flask_babel import Babel -from flask_login import LoginManager, logout_user, current_user, login_required +from flask_login import LoginManager, login_user, logout_user, current_user from tornado.wsgi import WSGIContainer from tornado.ioloop import IOLoop +from tornado import web, ioloop import tornado.web import tornado.httpserver from sockjs.tornado import SockJSRouter, SockJSConnection @@ -51,7 +52,6 @@ def get_id(self): def is_admin(self): return True - class Server(object): def __init__(self): self.request_handler = RHandler(self) @@ -59,6 +59,7 @@ def __init__(self): # Create flask instance for webserver self.flaskapp = Flask(__name__) + # Translation support self.flaskapp.config.from_pyfile('settings.cfg') self.babel = Babel(self.flaskapp) @@ -73,6 +74,8 @@ def __init__(self): # Variable to keep track of the active user self.active_session_key = None + # self.socket_session_keys = [] + self.client_sockets = set() # Token to authenticate socket connections # Client requests token via AJAX, server generates token if session is valid @@ -81,13 +84,12 @@ def __init__(self): # Setup app system self.plugin_base = pluginbase.PluginBase(package="opsoro.server.apps") - self.plugin_source = self.plugin_base.make_plugin_source( - searchpath=[get_path("./../apps")]) + self.plugin_source = self.plugin_base.make_plugin_source(searchpath=[get_path("./../apps")]) self.apps = {} self.activeapp = None - self.apps_can_register_bp = True # Make sure apps are only registered during setup - self.current_bp_app = "" # Keep track of current app for blueprint setup + self.apps_can_register_bp = True # Make sure apps are only registered during setup + self.current_bp_app = "" # Keep track of current app for blueprint setup # Socket callback dicts self.sockjs_connect_cb = {} @@ -166,9 +168,9 @@ def render_template(self, template, **kwargs): def run(self): # Setup SockJS - class OpsoroSocketConnection(SockJSConnection): + class AppSocketConnection(SockJSConnection): def __init__(conn, *args, **kwargs): - super(OpsoroSocketConnection, conn).__init__(*args, **kwargs) + super(AppSocketConnection, conn).__init__(*args, **kwargs) conn._authenticated = False conn._activeapp = self.activeapp @@ -191,8 +193,7 @@ def on_message(conn, msg): # Trigger connect callback if conn._activeapp in self.sockjs_connect_cb: - self.sockjs_connect_cb[conn._activeapp]( - conn) + self.sockjs_connect_cb[conn._activeapp](conn) return @@ -206,8 +207,7 @@ def on_message(conn, msg): action = message.pop("action", "") if conn._activeapp in self.sockjs_message_cb: if action in self.sockjs_message_cb[conn._activeapp]: - self.sockjs_message_cb[conn._activeapp][action]( - conn, message) + self.sockjs_message_cb[conn._activeapp][action](conn, message) def on_open(conn, info): # Connect callback is triggered when socket is authenticated. @@ -219,23 +219,67 @@ def on_close(conn): self.sockjs_disconnect_cb[conn._activeapp](conn) def send_error(conn, message): - return conn.send( - json.dumps({ - "action": "error", - "status": "error", - "message": message - })) + return conn.send(json.dumps({"action": "error", + "status": "error", + "message": message + })) def send_data(conn, action, data): msg = {"action": action, "status": "success"} msg.update(data) return conn.send(json.dumps(msg)) + class UserSocketConnection(SockJSConnection): + # clients = set() + + def __init__(conn, *args, **kwargs): + super(UserSocketConnection, conn).__init__(*args, **kwargs) + + # def _alive_ticker(conn): + # conn.send_data('tick', {'txt' : (len(conn.clients))}) + + def on_message(conn, msg): + # Attempt to decode JSON + conn.broadcast(self.client_sockets, msg) + print msg + pass + + def on_open(conn, info): + # conn.timeout = ioloop.PeriodicCallback(conn._alive_ticker, 1000) + # conn.timeout.start() + self.client_sockets.add(conn) + conn.update_users() + + def on_close(conn): + # conn.timeout.stop() + self.client_sockets.remove(conn) + conn.update_users() + + def send_error(conn, message): + return conn.send(json.dumps({"action": "error", + "status": "error", + "message": message + })) + + def send_data(conn, action, data): + msg = {"action": action, "status": "success"} + msg.update(data) + return conn.send(json.dumps(msg)) + + def broadcast_data(conn, action, data): + msg = {"action": action, "status": "success"} + msg.update(data) + return conn.broadcast(self.client_sockets, json.dumps(msg)) + + def update_users(conn): + # Print current client count + conn.broadcast_data('users', {'count': (len(self.client_sockets))}) + flaskwsgi = WSGIContainer(self.flaskapp) - socketrouter = SockJSRouter(OpsoroSocketConnection, "/sockjs") + app_socketrouter = SockJSRouter(AppSocketConnection, '/appsockjs') + self.user_socketrouter = SockJSRouter(UserSocketConnection, '/usersockjs') - tornado_app = tornado.web.Application(socketrouter.urls + [( - r".*", tornado.web.FallbackHandler, {"fallback": flaskwsgi})]) + tornado_app = tornado.web.Application(app_socketrouter.urls + self.user_socketrouter.urls + [(r".*", tornado.web.FallbackHandler, {"fallback": flaskwsgi})]) tornado_app.listen(80) # http_server = tornado.httpserver.HTTPServer(tornado_app, ssl_options={ @@ -243,7 +287,9 @@ def send_data(conn, action, data): # "keyfile": "/etc/ssl/private/server.key", # }) # http_server.listen(443) + try: + # ioloop.PeriodicCallback(UserSocketConnection.dump_stats, 1000).start() IOLoop.instance().start() except KeyboardInterrupt: self.stop_current_app() @@ -269,23 +315,20 @@ def protected_view(self, f): def wrapper(*args, **kwargs): if current_user.is_authenticated: if current_user.is_admin(): - if session[ - "active_session_key"] == self.active_session_key: + if session["active_session_key"] == self.active_session_key: # the actual page return f(*args, **kwargs) else: logout_user() session.pop("active_session_key", None) - flash( - "You have been logged out because a more recent session is active.") + if self.active_session_key is not None: + flash("You have been logged out because a more recent session is active.") return redirect(url_for("login")) else: - flash( - "You do not have permission to access the requested page. Please log in below.") + flash("You do not have permission to access the requested page. Please log in below.") return redirect(url_for("login")) else: - flash( - "You do not have permission to access the requested page. Please log in below.") + flash("You do not have permission to access the requested page. Please log in below.") return redirect(url_for("login")) return wrapper @@ -298,20 +341,17 @@ def wrapper(*args, **kwargs): # Protected page if current_user.is_authenticated: if current_user.is_admin(): - if session[ - "active_session_key"] != self.active_session_key: + if session["active_session_key"] != self.active_session_key: logout_user() session.pop("active_session_key", None) - flash( - "You have been logged out because a more recent session is active.") + if self.active_session_key is not None: + flash("You have been logged out because a more recent session is active.") return redirect(url_for("login")) else: - flash( - "You do not have permission to access the requested page. Please log in below.") + flash("You do not have permission to access the requested page. Please log in below.") return redirect(url_for("login")) else: - flash( - "You do not have permission to access the requested page. Please log in below.") + flash("You do not have permission to access the requested page. Please log in below.") return redirect(url_for("login")) # Check if app is active @@ -324,22 +364,19 @@ def wrapper(*args, **kwargs): data = { "app": {}, # "appname": appname, - "page_icon": self.apps[appname].config["icon"], + "page_icon": self.apps[appname].config["icon"], "page_caption": self.apps[appname].config["full_name"] } data["title"] = self.request_handler.title if self.activeapp in self.apps: # Another app is active - data["app"]["active"] = True - data["app"]["name"] = self.apps[self.activeapp].config[ - "full_name"] - data["app"]["icon"] = self.apps[self.activeapp].config[ - "icon"] - data["title"] += " - %s" % self.apps[ - self.activeapp].config["full_name"] + data["app"]["active"] = True + data["app"]["name"] = self.apps[self.activeapp].config["full_name"] + data["app"]["icon"] = self.apps[self.activeapp].config["icon"] + data["title"] += " - %s" % self.apps[self.activeapp].config["full_name"] else: # No app is active - data["app"]["active"] = False + data["app"]["active"] = False return render_template("app_not_active.html", **data) @@ -353,13 +390,10 @@ def wrapper(*args, **kwargs): # Protected page if current_user.is_authenticated: if current_user.is_admin(): - if session[ - "active_session_key"] != self.active_session_key: + if session["active_session_key"] != self.active_session_key: logout_user() session.pop("active_session_key", None) - return jsonify( - status="error", - message="You have been logged out because a more recent session is active.") + return jsonify(status="error", message="You have been logged out because a more recent session is active.") else: return jsonify( status="error", diff --git a/src/opsoro/server/request_handlers/__init__.py b/src/opsoro/server/request_handlers/__init__.py index 1761d6c..4c4cb46 100644 --- a/src/opsoro/server/request_handlers/__init__.py +++ b/src/opsoro/server/request_handlers/__init__.py @@ -2,6 +2,8 @@ from flask_login import login_user, logout_user, current_user from werkzeug.exceptions import default_exceptions +from sockjs.tornado import SockJSRouter, SockJSConnection + from functools import partial from opsoro.expression import Expression @@ -9,6 +11,7 @@ from opsoro.console_msg import * from opsoro.preferences import Preferences from opsoro.server.request_handlers.opsoro_data_requests import * +from opsoro.play import Play import random import os @@ -44,6 +47,22 @@ def get_id(self): def is_admin(self): return True +class OfflineUser(object): + def is_authenticated(self): + return True + + def is_active(self): + return True + + def is_anonymous(self): + return False + + def get_id(self): + return "admin" + + def is_admin(self): + return True + class RHandler(object): def __init__(self, server): @@ -57,111 +76,36 @@ def set_urls(self): protect = self.server.protected_view - self.server.flaskapp.add_url_rule("/", - "index", - protect(self.page_index), ) - self.server.flaskapp.add_url_rule( - "/login/", - "login", - self.page_login, - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule("/logout/", - "logout", - self.page_logout, ) - # self.server.flaskapp.add_url_rule( - # "/preferences", - # "preferences", - # protect(self.page_preferences), - # methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule("/sockjstoken/", - "sockjstoken", - self.page_sockjstoken, ) - self.server.flaskapp.add_url_rule("/shutdown/", - "shutdown", - protect(self.page_shutdown), ) - self.server.flaskapp.add_url_rule("/closeapp/", - "closeapp", - protect(self.page_closeapp), ) - self.server.flaskapp.add_url_rule("/openapp//", - "openapp", - protect(self.page_openapp), ) - # self.server.flaskapp.add_url_rule( - # "/app//files/", - # "files", - # protect(self.page_files), - # methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/", "index", protect(self.page_index), ) + self.server.flaskapp.add_url_rule("/login/", "login", self.page_login, methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/logout/", "logout", self.page_logout, ) + self.server.flaskapp.add_url_rule("/appsockjstoken/", "appsockjstoken", self.page_appsockjstoken, ) + self.server.flaskapp.add_url_rule("/shutdown/", "shutdown", protect(self.page_shutdown), ) + self.server.flaskapp.add_url_rule("/closeapp/", "closeapp", protect(self.page_closeapp), ) + self.server.flaskapp.add_url_rule("/openapp//", "openapp", protect(self.page_openapp), ) + # self.server.flaskapp.add_url_rule("/preferences", "preferences", protect(self.page_preferences), methods=["GET", "POST"], ) + # self.server.flaskapp.add_url_rule("/app//files/", "files", protect(self.page_files), methods=["GET", "POST"], ) + # ---------------------------------------------------------------------- # DOCUMENTS # ---------------------------------------------------------------------- - self.server.flaskapp.add_url_rule( - "/docs/data//", - "file_data", - protect(docs_file_data), - methods=["GET"], ) - self.server.flaskapp.add_url_rule( - "/docs/save//", - "file_save", - protect(docs_file_save), - methods=["POST"], ) - self.server.flaskapp.add_url_rule( - "/docs/delete//", - "file_delete", - protect(docs_file_delete), - methods=["POST"], ) - self.server.flaskapp.add_url_rule( - "/docs/list/", - "file_list", - protect(self.page_file_list), - methods=["GET"], ) + self.server.flaskapp.add_url_rule("/docs/data//", "file_data", protect(docs_file_data), methods=["GET"], ) + self.server.flaskapp.add_url_rule("/docs/save//", "file_save", protect(docs_file_save), methods=["POST"], ) + self.server.flaskapp.add_url_rule("/docs/delete//", "file_delete", protect(docs_file_delete), methods=["POST"], ) + self.server.flaskapp.add_url_rule("/docs/list/", "file_list", protect(self.page_file_list), methods=["GET"], ) # ---------------------------------------------------------------------- # ROBOT # ---------------------------------------------------------------------- - self.server.flaskapp.add_url_rule( - "/robot/", - "robot", - self.page_virtual, - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/config/", - "robot_config", - protect(robot_config_data), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/emotion/", - "robot_emotion", - protect(robot_emotion), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/dof/", - "robot_dof", - protect(robot_dof_data), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/dofs/", - "robot_dofs", - protect(robot_dofs_data), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/tts/", - "robot_tts", - protect(robot_tts), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/sound/", - "robot_sound", - protect(robot_sound), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/servo/", - "robot_servo", - protect(robot_servo), - methods=["GET", "POST"], ) - self.server.flaskapp.add_url_rule( - "/robot/stop/", - "robot_stop", - protect(robot_stop), - methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/", "robot", self.page_virtual, methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/config/", "robot_config", protect(robot_config_data), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/emotion/", "robot_emotion", protect(robot_emotion), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/dof/", "robot_dof", protect(robot_dof_data), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/dofs/", "robot_dofs", protect(robot_dofs_data), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/tts/", "robot_tts", protect(robot_tts), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/sound/", "robot_sound", protect(robot_sound), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/servo/", "robot_servo", protect(robot_servo), methods=["GET", "POST"], ) + self.server.flaskapp.add_url_rule("/robot/stop/", "robot_stop", protect(robot_stop), methods=["GET", "POST"], ) for _exc in default_exceptions: self.server.flaskapp.errorhandler(_exc)(self.show_errormessage) @@ -174,23 +118,16 @@ def render_template(self, template, **kwargs): kwargs["title"] = self.title # Set app variables if self.server.activeapp in self.server.apps: - kwargs["app"]["active"] = True - kwargs["app"]["name"] = self.server.apps[ - self.server.activeapp].config["full_name"].title() - kwargs["app"]["full_name"] = self.server.apps[ - self.server.activeapp].config["full_name"] - kwargs["app"]["formatted_name"] = self.server.apps[ - self.server.activeapp].config["formatted_name"] - kwargs["app"]["icon"] = self.server.apps[ - self.server.activeapp].config["icon"] - kwargs["app"]["color"] = self.server.apps[ - self.server.activeapp].config["color"] - kwargs["title"] += " - %s" % self.server.apps[ - self.server.activeapp].config["full_name"].title() - kwargs["page_icon"] = self.server.apps[ - self.server.activeapp].config["icon"] - kwargs["page_caption"] = self.server.apps[ - self.server.activeapp].config["full_name"] + app = self.server.apps[self.server.activeapp] + kwargs["app"]["active"] = True + kwargs["app"]["name"] = app.config["full_name"].title() + kwargs["app"]["full_name"] = app.config["full_name"] + kwargs["app"]["formatted_name"] = app.config["formatted_name"] + kwargs["app"]["icon"] = app.config["icon"] + kwargs["app"]["color"] = app.config["color"] + kwargs["title"] += " - %s" % app.config["full_name"].title() + kwargs["page_icon"] = app.config["icon"] + kwargs["page_caption"] = app.config["full_name"] else: kwargs["app"]["active"] = False @@ -218,7 +155,8 @@ def page_index(self): "full_name": app.config["full_name"], "formatted_name": app.config["formatted_name"], "icon": app.config["icon"], - "color": app.config['color']} + "color": app.config['color'] + } for appname in sorted(self.server.apps.keys()): app = self.server.apps[appname] @@ -227,46 +165,83 @@ def page_index(self): "formatted_name": app.config["formatted_name"], "icon": app.config["icon"], "color": app.config['color'], - "active": (appname == self.server.activeapp)}) + "active": (appname == self.server.activeapp) + }) return self.render_template("apps.html", **data) def page_login(self): - if request.method == "GET": - kwargs = {} - kwargs["title"] = self.title + " - Login" - kwargs["isuser"] = False - return render_template("login.html", **kwargs) - - password = request.form["password"] - - if password == Preferences.get( - "general", "password", default="RobotOpsoro"): - login_user(AdminUser()) + if Play.is_online(): + print_info('ONLINE MODE') + if request.method == "GET": + kwargs = {} + kwargs["title"] = self.title + " - Login" + kwargs["isbusy"] = self.server.active_session_key is not None + kwargs["isuser"] = False + return render_template("login.html", **kwargs) + + password = request.form["password"] + + if password == Preferences.get("general", "password", default="opsoro123"): + login_user(AdminUser()) + self.server.active_session_key = os.urandom(24) + session["active_session_key"] = self.server.active_session_key + + # self.server.user_socketrouter.broadcast(self.server.client_sockets, {'action': 'logout'}) + # for e in self.server.client_sockets: + # e.broadcast_data('logout', {}) + # break + + return redirect(url_for("index")) + else: + flash("Wrong password.") + return redirect(url_for("login")) + else: + print_info('OFFLINE MODE') + login_user(OfflineUser()) self.server.active_session_key = os.urandom(24) session["active_session_key"] = self.server.active_session_key return redirect(url_for("index")) - else: - flash("Wrong password.") - return redirect(url_for("login")) def page_logout(self): logout_user() + self.server.active_session_key = None + # if session["socket_session_key"] in self.server.socket_session_keys: + # self.server.socket_session_keys.remove(session["socket_session_key"]) + session.pop("active_session_key", None) + # session.pop("socket_session_key", None) + + # if 'socket_session_key' in session + # self.server.socket_sessions[self.server.socket_session_keys.index(session["socket_session_key"])].send_data('logout', {}) + # for socket_session in self.server.socket_sessions: + # socket_session.send_data('logout', {}) + # SockJSConnection.send('logout') + + flash("You have been logged out.") return redirect(url_for("login")) - def page_sockjstoken(self): + def page_appsockjstoken(self): if current_user.is_authenticated: if current_user.is_admin(): - if session[ - "active_session_key"] == self.server.active_session_key: + if session["active_session_key"] == self.server.active_session_key: # Valid user, generate a token self.server.sockjs_token = os.urandom(24) return base64.b64encode(self.server.sockjs_token) else: logout_user() session.pop("active_session_key", None) + + # Socket already exist + # if 'socket_session_key' in session and session["socket_session_key"] in self.server.socket_session_keys: + # # return base64.b64encode(session["socket_session_key"]) + # pass + # else: + # session["socket_session_key"] = os.urandom(24) + # self.server.socket_session_keys.append(session["socket_session_key"]) + # return base64.b64encode(session["socket_session_key"]) + return "" # Not a valid user, return nothing! def page_shutdown(self): @@ -290,14 +265,10 @@ def page_openapp(self, appname): self.server.stop_current_app() if appname in self.server.apps: - # robot_state: - # 0: Manual start/stop - # 1: Start robot automatically (alive feature according to preferences) - # 2: Start robot automatically and enable alive feature - # 3: Start robot automatically and disable alive feature - if self.server.apps[appname].config.has_key('robot_state'): - print_info(self.server.apps[appname].config['robot_state']) - if self.server.apps[appname].config['robot_state'] > 0: + # robot activation: + if self.server.apps[appname].config.has_key('activation'): + # print_info(self.server.apps[appname].config['activation']) + if self.server.apps[appname].config['activation'] >= Robot.Activation.AUTO: Robot.start() self.server.activeapp = appname diff --git a/src/opsoro/server/request_handlers/opsoro_data_requests.py b/src/opsoro/server/request_handlers/opsoro_data_requests.py index 3434d45..00f4c62 100644 --- a/src/opsoro/server/request_handlers/opsoro_data_requests.py +++ b/src/opsoro/server/request_handlers/opsoro_data_requests.py @@ -12,8 +12,7 @@ import os from functools import partial -get_abs_path = partial(os.path.join, - os.path.abspath(os.path.dirname(__file__))) +get_abs_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) try: import simplejson as json @@ -276,8 +275,8 @@ def robot_servo(): # print_info('pin: ' + str(servo_pin) + ', value: ' + str(servo_value)) with Hardware.lock: - Hardware.servo_enable() - Hardware.servo_set(servo_pin, servo_value) + Hardware.Servo.enable() + Hardware.Servo.set(servo_pin, servo_value) return json.dumps({'success': True}) @@ -294,8 +293,8 @@ def robot_servos(): values.append(constrain(value, 500, 2500)) with Hardware.lock: - Hardware.servo_enable() - Hardware.servo_set_all(values) + Hardware.Servo.enable() + Hardware.Servo.set_all(values) return json.dumps({'success': True}) diff --git a/src/opsoro/server/static/js/opsoro.js b/src/opsoro/server/static/js/opsoro.js index f08d908..08651e8 100644 --- a/src/opsoro/server/static/js/opsoro.js +++ b/src/opsoro/server/static/js/opsoro.js @@ -1,5 +1,3 @@ - - function showMainError(msg){ $("#errors").append("
" + msg + "×
"); $(document).foundation('alert', 'reflow'); @@ -133,6 +131,60 @@ function popupWindow(mylink, windowname) // ------------------------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------------------------- +// Socket connection +//-------------------------------------------------------------------------------------------------------- +// Setup websocket connection. +$(document).ready(function(){ + conn = null; + connReady = false; + conn = new SockJS("http://" + window.location.host + "/usersockjs"); + + conn.onopen = function(){ + // $.ajax({ + // url: "/appsockjstoken", + // cache: false + // }) + // .done(function(data) { + // conn.send(JSON.stringify({action: "authenticate", token: data})); + // console.log('SOCKET connected'); + // connReady = true; + // }); + }; + + conn.onmessage = function(e){ + console.log('SOCKET message'); + try { + var msg = $.parseJSON(e.data); + console.log(msg.action); + switch(msg.action){ + case "logout": + // alert('Another user logged in.') + if (window.location.href != '/login') { + window.location.href = '/'; + } + break; + case "info": + console.log(msg); + break; + case "users": + console.log(msg.count); + break; + } + } catch (e) { + console.log(e); + } finally { + + } + + }; + + conn.onclose = function(){ + console.log('SOCKET close'); + conn = null; + connReady = false; + }; +}); +// ------------------------------------------------------------------------------------------------------- // Robot control functions // ------------------------------------------------------------------------------------------------------- function robotSendReceiveConfig(config_data) diff --git a/src/opsoro/server/static/js/robot/virtual.js b/src/opsoro/server/static/js/robot/virtual.js index f78bf47..f8e2dfc 100644 --- a/src/opsoro/server/static/js/robot/virtual.js +++ b/src/opsoro/server/static/js/robot/virtual.js @@ -71,11 +71,11 @@ updateData = function() { // // Setup websocket connection. // var conn = null; // var connReady = false; -// conn = new SockJS("http://" + window.location.host + "/sockjs"); +// conn = new SockJS("http://" + window.location.host + "/appsockjs"); // // self.conn.onopen = function(){ // $.ajax({ -// url: "/sockjstoken", +// url: "/appsockjstoken", // cache: false // }) // .done(function(data) { diff --git a/src/opsoro/server/static/js/robot_new/virtual.js b/src/opsoro/server/static/js/robot_new/virtual.js index 414082f..81efcca 100644 --- a/src/opsoro/server/static/js/robot_new/virtual.js +++ b/src/opsoro/server/static/js/robot_new/virtual.js @@ -64,11 +64,11 @@ updateData = function() { // // Setup websocket connection. // var conn = null; // var connReady = false; -// conn = new SockJS("http://" + window.location.host + "/sockjs"); +// conn = new SockJS("http://" + window.location.host + "/appsockjs"); // // self.conn.onopen = function(){ // $.ajax({ -// url: "/sockjstoken", +// url: "/appsockjstoken", // cache: false // }) // .done(function(data) { diff --git a/src/opsoro/server/static/js/virtual_old.js b/src/opsoro/server/static/js/virtual_old.js index 442bbe9..e4cf6bb 100644 --- a/src/opsoro/server/static/js/virtual_old.js +++ b/src/opsoro/server/static/js/virtual_old.js @@ -71,11 +71,11 @@ updateData = function() { // // Setup websocket connection. // var conn = null; // var connReady = false; -// conn = new SockJS("http://" + window.location.host + "/sockjs"); +// conn = new SockJS("http://" + window.location.host + "/appsockjs"); // // self.conn.onopen = function(){ // $.ajax({ -// url: "/sockjstoken", +// url: "/appsockjstoken", // cache: false // }) // .done(function(data) { diff --git a/src/opsoro/server/templates/_body_scripts.html b/src/opsoro/server/templates/_body_scripts.html index 8022d55..ce6c9ff 100644 --- a/src/opsoro/server/templates/_body_scripts.html +++ b/src/opsoro/server/templates/_body_scripts.html @@ -1,6 +1,7 @@ + From 36cafc82a6039b1a8f965744f76ae4af03dfc169 Mon Sep 17 00:00:00 2001 From: Stan Date: Wed, 8 Mar 2017 10:49:07 +0100 Subject: [PATCH 08/60] Social update --- src/opsoro/apps/social_response/__init__.py | 26 +++++++++++---------- src/opsoro/config/preferences.yaml | 3 --- src/opsoro/sound/__init__.py | 7 ++---- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/opsoro/apps/social_response/__init__.py b/src/opsoro/apps/social_response/__init__.py index 8d490dd..a576e21 100644 --- a/src/opsoro/apps/social_response/__init__.py +++ b/src/opsoro/apps/social_response/__init__.py @@ -28,6 +28,7 @@ loop_t = None +loop_button_t = None # clientconn = None # running = False @@ -69,7 +70,7 @@ def get_page_data(page_id,fields,access_token): consumer_key = 'AcdgqgujzF06JF6zWrfwFeUfF' consumer_secret = 'ss0wVcBTFAT6nR6hXrqyyOcFOhpa2sNW4cIap9JOoepcch93ky' -twitterWords = ['@dekrook', '#opsoro'] +twitterWords = ['#opsoro'] auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) @@ -142,14 +143,17 @@ def Go_Crazy(text='', twitter=False, facebook=False): print_info('Done doing something!') -def Loop(): +def LoopButton(): time.sleep(0.05) # delay + while not loop_button_t.stopped(): + if Hardware.Analog.read_channel(0) > 1000: + Go_Crazy() + Sound.wait_for_sound() + loop_button_t.sleep(0.02) - # global clientconn - - # global counter +def Loop(): + time.sleep(0.05) # delay counter = 0 - # Initialize current Likes # global likes likes = 0 @@ -168,13 +172,7 @@ def Loop(): while not loop_t.stopped(): # if running: data = {} - print_info('Checking social...') - - # if clientconn: - # clientconn.send_data('updateelectrodes', - # {'electrodedata': data}) - try: # Facebook: new_likes = int(get_page_data(page_id, field, token)[field]) @@ -246,12 +244,16 @@ def setup(opsoroapp): def start(opsoroapp): global loop_t + global loop_button_t global myStream myStream.filter(track=twitterWords, async=True) loop_t = StoppableThread(target=Loop) + loop_button_t = StoppableThread(target=LoopButton) def stop(opsoroapp): global loop_t + global loop_button_t global myStream myStream.disconnect() loop_t.stop() + loop_button_t.stop() diff --git a/src/opsoro/config/preferences.yaml b/src/opsoro/config/preferences.yaml index e9592a7..9f77780 100644 --- a/src/opsoro/config/preferences.yaml +++ b/src/opsoro/config/preferences.yaml @@ -1,19 +1,16 @@ general: robot_name: robot password: opsoro123 - alive: enabled: false aliveness: 30 blink: true gaze: true - audio: master_volume: 60 tts_engine: espeak tts_language: en tts_gender: f - wireless: ssid: OPSORO-bot password: opsoro123 diff --git a/src/opsoro/sound/__init__.py b/src/opsoro/sound/__init__.py index 053a82b..e71c6ad 100644 --- a/src/opsoro/sound/__init__.py +++ b/src/opsoro/sound/__init__.py @@ -14,7 +14,6 @@ get_path = partial(os.path.join, os.path.abspath(os.path.dirname(__file__))) - class _Sound(object): def __init__(self): """ @@ -71,10 +70,8 @@ def play_file(self, filename): ["aplay", path], stdout=FNULL, stderr=subprocess.STDOUT) else: # self.playProcess = subprocess.Popen(["aplay", "-D", "hw:0,0", path], stdout=FNULL, stderr=subprocess.STDOUT) - self.playProcess = subprocess.Popen( - ["aplay", "-D", "hw:0,0", path], - stdout=FNULL, - stderr=subprocess.STDOUT) + self.playProcess = subprocess.Popen(["aplay", "-D", "hw:0,0", path], + stdout=FNULL, stderr=subprocess.STDOUT) def stop_sound(self): """ From e1b9f7e2b634b2fd886c4c40496903d898bd763f Mon Sep 17 00:00:00 2001 From: Stan Date: Wed, 8 Mar 2017 17:56:22 +0100 Subject: [PATCH 09/60] User Socket communication --- .../server/request_handlers/__init__.py | 10 +- src/opsoro/server/static/js/opsoro.js | 149 +++++++++--------- 2 files changed, 80 insertions(+), 79 deletions(-) diff --git a/src/opsoro/server/request_handlers/__init__.py b/src/opsoro/server/request_handlers/__init__.py index 4c4cb46..1046b2e 100644 --- a/src/opsoro/server/request_handlers/__init__.py +++ b/src/opsoro/server/request_handlers/__init__.py @@ -171,6 +171,10 @@ def page_index(self): return self.render_template("apps.html", **data) def page_login(self): + if 'active_session_key' in session: + if session['active_session_key'] == self.server.active_session_key: + return redirect(url_for('index')) + if Play.is_online(): print_info('ONLINE MODE') if request.method == "GET": @@ -188,9 +192,9 @@ def page_login(self): session["active_session_key"] = self.server.active_session_key # self.server.user_socketrouter.broadcast(self.server.client_sockets, {'action': 'logout'}) - # for e in self.server.client_sockets: - # e.broadcast_data('logout', {}) - # break + for e in self.server.client_sockets: + e.broadcast_data('refresh', {}) + break return redirect(url_for("index")) else: diff --git a/src/opsoro/server/static/js/opsoro.js b/src/opsoro/server/static/js/opsoro.js index 08651e8..3f2bd48 100644 --- a/src/opsoro/server/static/js/opsoro.js +++ b/src/opsoro/server/static/js/opsoro.js @@ -1,119 +1,119 @@ function showMainError(msg){ - $("#errors").append("
" + msg + "×
"); + $('#errors').append("
" + msg + "×
"); $(document).foundation('alert', 'reflow'); // setTimeout(function () { // showFiles(_CurrentPath, _OnlyFolders, _SaveFileView); // }, 200); } function showMainMessage(msg){ - $("#errors").append("
" + msg + "×
"); + $('#errors').append("
" + msg + "×
"); $(document).foundation('alert', 'reflow'); } function showMainSuccess(msg){ - $("#errors").append("
" + msg + "×
"); + $('#errors').append("
" + msg + "×
"); $(document).foundation('alert', 'reflow'); } function showPopup(sIcon, sTitle, sClass, sContent) { - $("#popup").addClass(sClass); - $("#popup .titlebar .titleicon span").addClass(sIcon); - $("#popup .titlebar .title").html(sTitle); + $('#popup').addClass(sClass); + $('#popup .titlebar .titleicon span').addClass(sIcon); + $('#popup .titlebar .title').html(sTitle); - if (sContent != ""){ - $("#popup .content").html(sContent); + if (sContent != ''){ + $('#popup .content').html(sContent); } - $("#popup .btnClose").off("click"); - $("#popup .btnClose").on("click", closePopup); + $('#popup .btnClose').off('click'); + $('#popup .btnClose').on('click', closePopup); // Open message popup - if (!$("#popup").hasClass("open")){ - $("#popup").foundation("reveal", "open"); + if (!$('#popup').hasClass('open')){ + $('#popup').foundation('reveal', 'open'); } } function closePopup() { - $("#popup").foundation("reveal", "close"); + $('#popup').foundation('reveal', 'close'); // Clear text & icon - $("#popup .titlebar .titleicon span").removeClass(); - $("#popup .titlebar .titleicon span").addClass("fa"); - $("#popup .titlebar .title").html(""); - $("#popup .content").html(""); + $('#popup .titlebar .titleicon span').removeClass(); + $('#popup .titlebar .titleicon span').addClass('fa'); + $('#popup .titlebar .title').html(''); + $('#popup .content').html(''); - $("#popup").removeClass(); - $("#popup").addClass("reveal-modal"); + $('#popup').removeClass(); + $('#popup').addClass('reveal-modal'); } function showMessagePopup(sIcon, sTitle, sText, handlers) { - $("#message_popup .titlebar .titleicon span").addClass(sIcon); - $("#message_popup .titlebar .title").html(sTitle); - $("#message_popup .content .text").html(sText); + $('#message_popup .titlebar .titleicon span').addClass(sIcon); + $('#message_popup .titlebar .title').html(sTitle); + $('#message_popup .content .text').html(sText); data = {}; // Input enabling if (handlers.inputText != undefined){ - $("#message_popup .inputText").removeClass("hide"); - $("#message_popup .inputText").on("input", handlers.inputText); + $('#message_popup .inputText').removeClass('hide'); + $('#message_popup .inputText').on('input', handlers.inputText); } // Button click handlers if (handlers.btnOk != undefined){ - $("#message_popup .btnOk").removeClass("hide"); - $("#message_popup .btnOk").on("click", handlers.btnOk); + $('#message_popup .btnOk').removeClass('hide'); + $('#message_popup .btnOk').on('click', handlers.btnOk); } if (handlers.btnYes != undefined){ - $("#message_popup .btnYes").removeClass("hide"); - $("#message_popup .btnYes").on("click", handlers.btnYes); + $('#message_popup .btnYes').removeClass('hide'); + $('#message_popup .btnYes').on('click', handlers.btnYes); } if (handlers.btnNo != undefined){ - $("#message_popup .btnNo").removeClass("hide"); - $("#message_popup .btnNo").on("click", handlers.btnNo); + $('#message_popup .btnNo').removeClass('hide'); + $('#message_popup .btnNo').on('click', handlers.btnNo); } if (handlers.btnSave != undefined){ - $("#message_popup .btnSave").removeClass("hide"); - $("#message_popup .btnSave").on("click", handlers.btnSave); + $('#message_popup .btnSave').removeClass('hide'); + $('#message_popup .btnSave').on('click', handlers.btnSave); } if (handlers.btnCancel != undefined){ - $("#message_popup .btnCancel").removeClass("hide"); - $("#message_popup .btnCancel").on("click", handlers.btnCancel); + $('#message_popup .btnCancel').removeClass('hide'); + $('#message_popup .btnCancel').on('click', handlers.btnCancel); } - $("#message_popup .btnClose").off("click"); - $("#message_popup .btnClose").on("click", closeMessagePopup); + $('#message_popup .btnClose').off('click'); + $('#message_popup .btnClose').on('click', closeMessagePopup); // Open message popup - if (!$("#message_popup").hasClass("open")){ - $("#message_popup").foundation("reveal", "open"); + if (!$('#message_popup').hasClass('open')){ + $('#message_popup').foundation('reveal', 'open'); } } function closeMessagePopup() { - $("#message_popup").foundation("reveal", "close"); + $('#message_popup').foundation('reveal', 'close'); // Clear text & icon - $("#message_popup .titlebar .titleicon span").removeClass(); - $("#message_popup .titlebar .titleicon span").addClass("fa"); - $("#message_popup .titlebar .title").html(""); - $("#message_popup .content .text").html(""); + $('#message_popup .titlebar .titleicon span').removeClass(); + $('#message_popup .titlebar .titleicon span').addClass('fa'); + $('#message_popup .titlebar .title').html(''); + $('#message_popup .content .text').html(''); // Clear inputs - $("#message_popup .inputText").val(""); + $('#message_popup .inputText').val(''); // Hide inputs - $("#message_popup .inputText").addClass("hide"); + $('#message_popup .inputText').addClass('hide'); // Hide buttons - $("#message_popup .btnOk").addClass("hide"); - $("#message_popup .btnYes").addClass("hide"); - $("#message_popup .btnNo").addClass("hide"); - $("#message_popup .btnSave").addClass("hide"); - $("#message_popup .btnCancel").addClass("hide"); + $('#message_popup .btnOk').addClass('hide'); + $('#message_popup .btnYes').addClass('hide'); + $('#message_popup .btnNo').addClass('hide'); + $('#message_popup .btnSave').addClass('hide'); + $('#message_popup .btnCancel').addClass('hide'); // Remove click handlers - $("#message_popup .btnOk").off("click"); - $("#message_popup .btnYes").off("click"); - $("#message_popup .btnNo").off("click"); - $("#message_popup .btnSave").off("click"); - $("#message_popup .btnCancel").off("click"); + $('#message_popup .btnOk').off('click'); + $('#message_popup .btnYes').off('click'); + $('#message_popup .btnNo').off('click'); + $('#message_popup .btnSave').off('click'); + $('#message_popup .btnCancel').off('click'); } function popupWindow(mylink, windowname) @@ -137,15 +137,15 @@ function popupWindow(mylink, windowname) $(document).ready(function(){ conn = null; connReady = false; - conn = new SockJS("http://" + window.location.host + "/usersockjs"); + conn = new SockJS('http://' + window.location.host + '/usersockjs'); conn.onopen = function(){ // $.ajax({ - // url: "/appsockjstoken", + // url: '/appsockjstoken', // cache: false // }) // .done(function(data) { - // conn.send(JSON.stringify({action: "authenticate", token: data})); + // conn.send(JSON.stringify({action: 'authenticate', token: data})); // console.log('SOCKET connected'); // connReady = true; // }); @@ -157,16 +157,13 @@ $(document).ready(function(){ var msg = $.parseJSON(e.data); console.log(msg.action); switch(msg.action){ - case "logout": - // alert('Another user logged in.') - if (window.location.href != '/login') { - window.location.href = '/'; - } + case 'refresh': + location.reload(); break; - case "info": + case 'info': console.log(msg); break; - case "users": + case 'users': console.log(msg.count); break; } @@ -288,9 +285,9 @@ function robotSendServo(pin, value) function robotSendTTS(text) { $.ajax({ - dataType: "json", - type: "GET", - url: "/robot/tts/", + dataType: 'json', + type: 'GET', + url: '/robot/tts/', data: {t: text}, success: function(data){ if (!data.success) { @@ -303,12 +300,12 @@ function robotSendTTS(text) function robotSendSound(soundName) { $.ajax({ - dataType: "json", - type: "GET", - url: "/robot/sound/", + dataType: 'json', + type: 'GET', + url: '/robot/sound/', data: {s: soundName}, success: function(data){ - if(data.status == "error"){ + if(data.status == 'error'){ showMainError(data.message); } @@ -319,11 +316,11 @@ function robotSendSound(soundName) function robotSendStop() { $.ajax({ - dataType: "json", - type: "GET", - url: "/robot/stop/", + dataType: 'json', + type: 'GET', + url: '/robot/stop/', success: function(data){ - if(data.status == "error"){ + if(data.status == 'error'){ showMainError(data.message); } From fb6dbfd85427a596ad06b421f338fd20bcc8bec6 Mon Sep 17 00:00:00 2001 From: Stan Date: Wed, 8 Mar 2017 17:56:38 +0100 Subject: [PATCH 10/60] Style fixes --- src/opsoro/apps/social_script/static/app.css | 18 ++++++----- src/opsoro/server/static/css/opsoro.css | 28 ++++++++-------- src/opsoro/server/static/css/opsoro.min.css | 2 +- src/opsoro/server/static/css/opsoro.scss | 34 +++++++++++--------- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/opsoro/apps/social_script/static/app.css b/src/opsoro/apps/social_script/static/app.css index 1f024ff..2780ef5 100644 --- a/src/opsoro/apps/social_script/static/app.css +++ b/src/opsoro/apps/social_script/static/app.css @@ -242,7 +242,8 @@ padding-top: 1rem; border-radius: 50%; - background-color: #43ac6a; + /*background-color: #43ac6a;*/ + background-color: transparent; } .voiceline .playbutton a span @@ -258,22 +259,23 @@ .voiceline .playbutton a:hover { - background-color: #368a55; + /*background-color: #368a55;*/ + /*background-color: transparent;*/ } .voiceline .playbutton.used .bg { - background: #ddd; + background: #aaa; } .voiceline .playbutton.used a { - background: #b2afa1; + /*background: #b2afa1;*/ } .voiceline .playbutton.used a:hover { - background-color: #545454; + /*background-color: #545454;*/ } .voiceline .playbutton.active .bg @@ -288,17 +290,17 @@ border-right: .6rem solid rgba(34, 181, 115, .41); border-bottom: .6rem solid rgba(34, 181, 115, .41); border-left: .6rem solid rgba(34, 181, 115, .7); - background: #fff; + background: #b2afa1; } .voiceline .playbutton.active a { - background: #43ac6a; + /*background: #43ac6a;*/ } .voiceline .playbutton.active a:hover { - background-color: #368a55; + /*background-color: #368a55;*/ } .voiceline .content diff --git a/src/opsoro/server/static/css/opsoro.css b/src/opsoro/server/static/css/opsoro.css index 9f2a063..a5dc49a 100644 --- a/src/opsoro/server/static/css/opsoro.css +++ b/src/opsoro/server/static/css/opsoro.css @@ -246,16 +246,15 @@ fieldset { top: 0; overflow: hidden; max-width: 75rem; - margin-left: auto; - margin-right: auto; + margin: 0 auto 1rem; background-color: #FFF; color: #27292a; padding: 0 0.7rem; border-bottom-left-radius: 1rem; border-bottom-right-radius: 1rem; - -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); - -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); - box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } #header_play div { float: left; padding: 0; } @@ -411,9 +410,9 @@ fieldset { opacity: 1; background-color: #FFF; border-radius: 0.8rem; - -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); - -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); - box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, 0.75); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } .apps .app_container .app_button .app_icon { font: normal normal normal 14px/1 FontAwesome; font-size: 5rem; @@ -446,9 +445,9 @@ fieldset { border: 0; border-radius: 0.75rem; background: #fff; - -webkit-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, 0.75); - -moz-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, 0.75); - box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, 0.75); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } .reveal-modal .titlebar { font-size: 2rem; font-weight: bold; @@ -504,10 +503,13 @@ fieldset { .actionbar { min-height: 4rem; - margin: .5rem 0 1rem; + margin: -0.5rem 0 1rem; padding: 0.5rem 1rem; background: #23774e; - border-radius: 0.5rem; } + border-radius: 0.5rem; + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } .actionbar .action { display: inline-block; min-width: 3rem; diff --git a/src/opsoro/server/static/css/opsoro.min.css b/src/opsoro/server/static/css/opsoro.min.css index 4a3b7d0..9efeb9f 100644 --- a/src/opsoro/server/static/css/opsoro.min.css +++ b/src/opsoro/server/static/css/opsoro.min.css @@ -1 +1 @@ -@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Regular.ttf") format("truetype");font-style:normal;font-weight:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-DemiBold.ttf") format("truetype");font-weight:500;font-style:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Bold.ttf") format("truetype");font-weight:700;font-style:normal}body{height:auto;color:#27292a;background:#F2F2F2;background-image:url("../images/background/bg_tiled_dark.png");font-family:'Avenir Next' !important;font-size:1.1rem}article,div,h1,h2,h3,h4,h5,h6,p,section,span{font-family:'Avenir Next'}hr{margin:10000}a{outline:0}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}footer{height:4rem}footer .container{margin-top:0}footer img{display:block;width:8rem;margin:0.5rem auto;opacity:0.75}h1{font-size:3rem;text-align:center;font-weight:bold;color:#6e00ff}h2{margin:0.5rem 0;font-size:2rem;font-weight:bold;color:#27292a}h3{font-size:1.2rem;font-weight:bold}img{margin-left:auto;margin-right:auto;padding:0}article{padding:1rem;margin:0 auto;text-align:justify}p{padding:0 1rem;margin:0.5rem 0}a{text-decoration:none;font-weight:bold;color:#27292a;outline:medium none !important}a:active,a:focus,a:hover{text-decoration:none;color:#15e678 !important}a:visited{text-decoration:none}fieldset legend{background-color:transparent}fieldset{margin-top:0 !important}.tabs{width:100% !important;max-width:100% !important}.tabs-content .content{padding-top:0}.nav{width:100%}.nav img{float:left}.nav ul{float:right}.nav ul li{float:left;margin:1rem;list-style-type:none}.nav ul li a,.nav ul li a:visited{font-size:1rem;font-weight:bold;text-decoration:none;text-transform:uppercase;color:#fff}.row{max-width:75rem}.color_green{color:#15e678}.color_blue{color:#36c9ff}.color_orange{color:#ffaf19}.color_red{color:#ff517e}.color_purple{color:#6e00ff}.color_yellow{color:#fff000}.color_gray_light{color:#F2F2F2;background-color:#27292a}.color_gray_light h1{color:#F2F2F2}.color_gray_light a{color:#F2F2F2}.color_gray_dark{color:#27292a}.color_white{color:#fff}.text_caps{text-transform:uppercase}.text_center{text-align:center;vertical-align:middle}.box_center{float:none;margin-left:auto;margin-right:auto}.side_right{float:right;text-align:right}.full_width{max-width:100%}.full_width *{max-width:75rem;margin-left:auto;margin-right:auto}.nopadding{padding:0}.circle{-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%}.rectangle{-webkit-border-radius:1rem;-moz-border-radius:1rem;border-radius:1rem}.btn{font-size:1rem;padding:0.5rem 2rem;height:2.3125rem;background-color:#6e00ff;color:#F2F2F2;font-weight:bold}.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:none;margin-left:auto;margin-right:auto}.columns+.columns:last-child{float:left}#header_play{position:relative;top:0;overflow:hidden;max-width:75rem;margin-left:auto;margin-right:auto;background-color:#fff;color:#27292a;padding:0 0.7rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem;-webkit-box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75);-moz-box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75);box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75)}#header_play div{float:left;padding:0}#header_play i{float:left}#header_play p{float:left;padding:0}#header_play .side_right{float:right}#header_play .text_center{float:none;margin-left:auto;margin-right:auto;width:10rem}#header_play ul{text-align:center;margin:0}#header_play ul li{margin:0}#header_play i{margin:0.5rem 0.5rem 0 0;font-size:3.3rem}#header_play #status{text-transform:uppercase;font-weight:bold}#header_play #comment i{margin:0.2rem 0.2rem 0 0;font-size:1.1rem}#header_play a{margin:0;padding:0;color:#27292a}#header_play a i{margin:1rem 0 0.5rem 1rem;font-size:2.3rem}#header_play .status{margin:0.5rem 0}.sidebar_left,.sidebar_right{position:fixed;z-index:8;top:50px;bottom:0;left:0;display:block;overflow:visible;overflow:auto;max-width:13rem;padding:1rem;color:#000;background-color:rgba(255,255,255,0.5);-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.sidebar_left:empty,.sidebar_right:empty{display:none}.sidebar_right{right:0;left:auto}.container{position:relative;max-width:75rem;margin-top:0.5rem;margin-right:auto;margin-left:auto;padding:0}.announcements{position:fixed;z-index:10;right:0;bottom:0;left:0;display:block;width:100%;text-align:center}.announcement{position:relative;max-width:40rem;margin-top:1rem;margin-right:auto;margin-left:auto;padding:0.75rem;text-align:center;-webkit-border-top-left-radius:0.8rem;-moz-border-radius-topleft:0.8rem;border-top-left-radius:0.8rem;-webkit-border-top-right-radius:0.8rem;-moz-border-radius-topright:0.8rem;border-top-right-radius:0.8rem;color:#fff;background-color:#333;-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.announcement .btn{font-size:2rem;position:absolute;top:0;right:0;display:block;width:2.75rem;height:2.75rem;padding:0;color:#fff;border-style:none;background-color:transparent}.announcement .btn:active,.announcement .btn:hover{font-size:2.1rem;color:#fff;border-style:none;background-color:transparent}.apps{max-width:100%;margin-right:auto;margin-left:auto;padding:0}.apps .app_container{margin:0 auto 1rem}.apps .app_container a{float:none;color:#27292a}.apps .app_container a:hover{text-decoration:none;color:#27292a !important}.apps .app_container a:hover .app_icon{font-size:5.5rem;margin:1.75rem auto}.apps .app_container .app_button{position:relative;display:block;overflow:hidden;width:9rem;height:9rem;margin:0.5rem auto;text-align:center;vertical-align:middle;opacity:1;background-color:#fff;border-radius:0.8rem;-webkit-box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75);-moz-box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75);box-shadow:2px 2px 3px 1px rgba(0,0,0,0.75)}.apps .app_container .app_button .app_icon{font:normal normal normal 14px/1 FontAwesome;font-size:5rem;display:inline-block;width:100%;margin:2rem auto}.apps .app_container .app_button .app_banner{position:absolute;display:block;bottom:0;left:0;width:100%;height:1rem}.apps .app_container .app_label{font-size:1.2rem;font-weight:normal;overflow:hidden;width:100%;text-align:center}.reveal-modal{position:absolute;top:1rem;right:1rem;left:1rem;margin-right:auto;margin-left:auto;padding:0;color:#4d4d4d;border:0;border-radius:0.75rem;background:#fff;-webkit-box-shadow:0.5rem 0.5rem 0 0 rgba(50,50,50,0.75);-moz-box-shadow:0.5rem 0.5rem 0 0 rgba(50,50,50,0.75);box-shadow:0.5rem 0.5rem 0 0 rgba(50,50,50,0.75)}.reveal-modal .titlebar{font-size:2rem;font-weight:bold;position:relative;padding:0.5rem;text-align:center;color:#fff;border-bottom:0.25rem solid #545454;-webkit-border-top-left-radius:0.5rem;-moz-border-radius-topleft:0.5rem;border-top-left-radius:0.5rem;-webkit-border-top-right-radius:0.5rem;-moz-border-radius-topright:0.5rem;border-top-right-radius:0.5rem;background:#b2afa1}.reveal-modal .titlebar.red{border-bottom:0.25rem solid #79261d;background:#b2382a}.reveal-modal .titlebar.green{border-bottom:0.25rem solid #26791d;background:#38b22a}.reveal-modal .content{padding:1rem}.reveal-modal .close-reveal{font-size:2rem;font-weight:normal;position:absolute;top:1rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .close-reveal:hover{font-size:2.5rem;top:0.75rem;left:0.75rem}.reveal-modal .btnClose{font-size:2rem;font-weight:normal;position:absolute;top:0.5rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .btnClose:hover{font-size:2.5rem;top:0.25rem;left:0.75rem}.float_right{float:right}.actionbar{min-height:4rem;margin:.5rem 0 1rem;padding:0.5rem 1rem;background:#23774e;border-radius:0.5rem}.actionbar .action{display:inline-block;min-width:3rem;padding:0 0.5rem;text-align:center;color:#fff;-webkit-border-radius:0.25rem;-moz-border-radius:0.25rem;border-radius:0.25rem}.actionbar .action .text{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar .action.active,.actionbar .action:hover{color:#4d4d4d;background:#fff}.actionbar .spacer{display:inline-block;width:2rem}.actionbar .filebox{display:inline-block;overflow:hidden;min-width:7rem;max-width:20rem;white-space:nowrap;text-overflow:ellipsis;color:#fff}.actionbar .filebox .filename{font-weight:bold;text-transform:uppercase}.actionbar .filebox .status{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar:empty{display:none}.contentwrapper *{font:12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important}.fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#F2F2F2;padding:0;margin:0;z-index:9}.fullscreen .contentwrapper{height:calc(100vh - 4rem - 4.15rem)}.fullscreen .console{border-bottom-right-radius:0;border-bottom-left-radius:0}.fullscreen .actionbar{margin:0;border-radius:0}.fullscreen .container{margin:0;padding:0;max-width:100%;width:100%;height:100%}.filebrowser{position:fixed;right:1rem;bottom:3rem;left:1rem}.filebrowser .content{position:absolute;top:4rem;bottom:0;width:100%}.filebrowser .actionbar .actionBarItem{position:relative;float:left;min-width:4rem}.filebrowser .foldercontent{position:absolute;top:4.5rem;bottom:0.5rem;left:0;overflow-x:hidden;overflow-y:scroll;width:100%;padding:0 3rem 3rem}.filebrowser .foldercontent .button{font-size:1.5rem;width:5rem;margin-left:0.5rem;padding:0}.filebrowser .foldercontent .alert{width:2.5rem}.filebrowser .foldercontent .browseritem{width:100%;min-height:2rem;margin:0.1rem;padding:0.2rem;border-radius:0.25rem}.filebrowser .foldercontent .browseritem:hover{background-color:#f2f2f2}.filebrowser .foldercontent .browseritem:hover .browseritemoptions{opacity:1}.filebrowser .foldercontent .browseritem a{margin:0}.filebrowser .foldercontent .browseritem .browseritemname{font-size:1.5rem;font-weight:bold;margin-left:2rem}.filebrowser .foldercontent .browseritem .browseritemoptions{float:right;padding:0.15rem}.filebrowser .foldercontent .browseritem .browseritemoptions{-webkit-transition:opacity 0.1s ease-in-out;-moz-transition:opacity 0.1s ease-in-out;transition:opacity 0.1s ease-in-out;opacity:0}#message_popup .content .buttons{position:relative;text-align:center}#message_popup .content .buttons .button{margin-right:1rem;margin-left:1rem} +@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Regular.ttf") format("truetype");font-style:normal;font-weight:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-DemiBold.ttf") format("truetype");font-weight:500;font-style:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Bold.ttf") format("truetype");font-weight:700;font-style:normal}body{height:auto;color:#27292a;background:#F2F2F2;background-image:url("../images/background/bg_tiled_dark.png");font-family:'Avenir Next' !important;font-size:1.1rem}article,div,h1,h2,h3,h4,h5,h6,p,section,span{font-family:'Avenir Next'}hr{margin:10000}a{outline:0}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}footer{height:4rem}footer .container{margin-top:0}footer img{display:block;width:8rem;margin:0.5rem auto;opacity:0.75}h1{font-size:3rem;text-align:center;font-weight:bold;color:#6e00ff}h2{margin:0.5rem 0;font-size:2rem;font-weight:bold;color:#27292a}h3{font-size:1.2rem;font-weight:bold}img{margin-left:auto;margin-right:auto;padding:0}article{padding:1rem;margin:0 auto;text-align:justify}p{padding:0 1rem;margin:0.5rem 0}a{text-decoration:none;font-weight:bold;color:#27292a;outline:medium none !important}a:active,a:focus,a:hover{text-decoration:none;color:#15e678 !important}a:visited{text-decoration:none}fieldset legend{background-color:transparent}fieldset{margin-top:0 !important}.tabs{width:100% !important;max-width:100% !important}.tabs-content .content{padding-top:0}.nav{width:100%}.nav img{float:left}.nav ul{float:right}.nav ul li{float:left;margin:1rem;list-style-type:none}.nav ul li a,.nav ul li a:visited{font-size:1rem;font-weight:bold;text-decoration:none;text-transform:uppercase;color:#fff}.row{max-width:75rem}.color_green{color:#15e678}.color_blue{color:#36c9ff}.color_orange{color:#ffaf19}.color_red{color:#ff517e}.color_purple{color:#6e00ff}.color_yellow{color:#fff000}.color_gray_light{color:#F2F2F2;background-color:#27292a}.color_gray_light h1{color:#F2F2F2}.color_gray_light a{color:#F2F2F2}.color_gray_dark{color:#27292a}.color_white{color:#fff}.text_caps{text-transform:uppercase}.text_center{text-align:center;vertical-align:middle}.box_center{float:none;margin-left:auto;margin-right:auto}.side_right{float:right;text-align:right}.full_width{max-width:100%}.full_width *{max-width:75rem;margin-left:auto;margin-right:auto}.nopadding{padding:0}.circle{-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%}.rectangle{-webkit-border-radius:1rem;-moz-border-radius:1rem;border-radius:1rem}.btn{font-size:1rem;padding:0.5rem 2rem;height:2.3125rem;background-color:#6e00ff;color:#F2F2F2;font-weight:bold}.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:none;margin-left:auto;margin-right:auto}.columns+.columns:last-child{float:left}#header_play{position:relative;top:0;overflow:hidden;max-width:75rem;margin:0 auto 1rem;background-color:#fff;color:#27292a;padding:0 0.7rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}#header_play div{float:left;padding:0}#header_play i{float:left}#header_play p{float:left;padding:0}#header_play .side_right{float:right}#header_play .text_center{float:none;margin-left:auto;margin-right:auto;width:10rem}#header_play ul{text-align:center;margin:0}#header_play ul li{margin:0}#header_play i{margin:0.5rem 0.5rem 0 0;font-size:3.3rem}#header_play #status{text-transform:uppercase;font-weight:bold}#header_play #comment i{margin:0.2rem 0.2rem 0 0;font-size:1.1rem}#header_play a{margin:0;padding:0;color:#27292a}#header_play a i{margin:1rem 0 0.5rem 1rem;font-size:2.3rem}#header_play .status{margin:0.5rem 0}.sidebar_left,.sidebar_right{position:fixed;z-index:8;top:50px;bottom:0;left:0;display:block;overflow:visible;overflow:auto;max-width:13rem;padding:1rem;color:#000;background-color:rgba(255,255,255,0.5);-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.sidebar_left:empty,.sidebar_right:empty{display:none}.sidebar_right{right:0;left:auto}.container{position:relative;max-width:75rem;margin-top:0.5rem;margin-right:auto;margin-left:auto;padding:0}.announcements{position:fixed;z-index:10;right:0;bottom:0;left:0;display:block;width:100%;text-align:center}.announcement{position:relative;max-width:40rem;margin-top:1rem;margin-right:auto;margin-left:auto;padding:0.75rem;text-align:center;-webkit-border-top-left-radius:0.8rem;-moz-border-radius-topleft:0.8rem;border-top-left-radius:0.8rem;-webkit-border-top-right-radius:0.8rem;-moz-border-radius-topright:0.8rem;border-top-right-radius:0.8rem;color:#fff;background-color:#333;-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.announcement .btn{font-size:2rem;position:absolute;top:0;right:0;display:block;width:2.75rem;height:2.75rem;padding:0;color:#fff;border-style:none;background-color:transparent}.announcement .btn:active,.announcement .btn:hover{font-size:2.1rem;color:#fff;border-style:none;background-color:transparent}.apps{max-width:100%;margin-right:auto;margin-left:auto;padding:0}.apps .app_container{margin:0 auto 1rem}.apps .app_container a{float:none;color:#27292a}.apps .app_container a:hover{text-decoration:none;color:#27292a !important}.apps .app_container a:hover .app_icon{font-size:5.5rem;margin:1.75rem auto}.apps .app_container .app_button{position:relative;display:block;overflow:hidden;width:9rem;height:9rem;margin:0.5rem auto;text-align:center;vertical-align:middle;opacity:1;background-color:#fff;border-radius:0.8rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.apps .app_container .app_button .app_icon{font:normal normal normal 14px/1 FontAwesome;font-size:5rem;display:inline-block;width:100%;margin:2rem auto}.apps .app_container .app_button .app_banner{position:absolute;display:block;bottom:0;left:0;width:100%;height:1rem}.apps .app_container .app_label{font-size:1.2rem;font-weight:normal;overflow:hidden;width:100%;text-align:center}.reveal-modal{position:absolute;top:1rem;right:1rem;left:1rem;margin-right:auto;margin-left:auto;padding:0;color:#4d4d4d;border:0;border-radius:0.75rem;background:#fff;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.reveal-modal .titlebar{font-size:2rem;font-weight:bold;position:relative;padding:0.5rem;text-align:center;color:#fff;border-bottom:0.25rem solid #545454;-webkit-border-top-left-radius:0.5rem;-moz-border-radius-topleft:0.5rem;border-top-left-radius:0.5rem;-webkit-border-top-right-radius:0.5rem;-moz-border-radius-topright:0.5rem;border-top-right-radius:0.5rem;background:#b2afa1}.reveal-modal .titlebar.red{border-bottom:0.25rem solid #79261d;background:#b2382a}.reveal-modal .titlebar.green{border-bottom:0.25rem solid #26791d;background:#38b22a}.reveal-modal .content{padding:1rem}.reveal-modal .close-reveal{font-size:2rem;font-weight:normal;position:absolute;top:1rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .close-reveal:hover{font-size:2.5rem;top:0.75rem;left:0.75rem}.reveal-modal .btnClose{font-size:2rem;font-weight:normal;position:absolute;top:0.5rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .btnClose:hover{font-size:2.5rem;top:0.25rem;left:0.75rem}.float_right{float:right}.actionbar{min-height:4rem;margin:-0.5rem 0 1rem;padding:0.5rem 1rem;background:#23774e;border-radius:0.5rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.actionbar .action{display:inline-block;min-width:3rem;padding:0 0.5rem;text-align:center;color:#fff;-webkit-border-radius:0.25rem;-moz-border-radius:0.25rem;border-radius:0.25rem}.actionbar .action .text{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar .action.active,.actionbar .action:hover{color:#4d4d4d;background:#fff}.actionbar .spacer{display:inline-block;width:2rem}.actionbar .filebox{display:inline-block;overflow:hidden;min-width:7rem;max-width:20rem;white-space:nowrap;text-overflow:ellipsis;color:#fff}.actionbar .filebox .filename{font-weight:bold;text-transform:uppercase}.actionbar .filebox .status{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar:empty{display:none}.contentwrapper *{font:12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important}.fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#F2F2F2;padding:0;margin:0;z-index:9}.fullscreen .contentwrapper{height:calc(100vh - 4rem - 4.15rem)}.fullscreen .console{border-bottom-right-radius:0;border-bottom-left-radius:0}.fullscreen .actionbar{margin:0;border-radius:0}.fullscreen .container{margin:0;padding:0;max-width:100%;width:100%;height:100%}.filebrowser{position:fixed;right:1rem;bottom:3rem;left:1rem}.filebrowser .content{position:absolute;top:4rem;bottom:0;width:100%}.filebrowser .actionbar .actionBarItem{position:relative;float:left;min-width:4rem}.filebrowser .foldercontent{position:absolute;top:4.5rem;bottom:0.5rem;left:0;overflow-x:hidden;overflow-y:scroll;width:100%;padding:0 3rem 3rem}.filebrowser .foldercontent .button{font-size:1.5rem;width:5rem;margin-left:0.5rem;padding:0}.filebrowser .foldercontent .alert{width:2.5rem}.filebrowser .foldercontent .browseritem{width:100%;min-height:2rem;margin:0.1rem;padding:0.2rem;border-radius:0.25rem}.filebrowser .foldercontent .browseritem:hover{background-color:#f2f2f2}.filebrowser .foldercontent .browseritem:hover .browseritemoptions{opacity:1}.filebrowser .foldercontent .browseritem a{margin:0}.filebrowser .foldercontent .browseritem .browseritemname{font-size:1.5rem;font-weight:bold;margin-left:2rem}.filebrowser .foldercontent .browseritem .browseritemoptions{float:right;padding:0.15rem}.filebrowser .foldercontent .browseritem .browseritemoptions{-webkit-transition:opacity 0.1s ease-in-out;-moz-transition:opacity 0.1s ease-in-out;transition:opacity 0.1s ease-in-out;opacity:0}#message_popup .content .buttons{position:relative;text-align:center}#message_popup .content .buttons .button{margin-right:1rem;margin-left:1rem} diff --git a/src/opsoro/server/static/css/opsoro.scss b/src/opsoro/server/static/css/opsoro.scss index da182db..331eb17 100644 --- a/src/opsoro/server/static/css/opsoro.scss +++ b/src/opsoro/server/static/css/opsoro.scss @@ -35,9 +35,9 @@ $rounding_medium: 1rem; // box-shadow: 0 0 8px rgba(0, 0, 0, .8); // -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, .8); // -moz-box-shadow: 0 0 8px rgba(0, 0, 0, .8); - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); - box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); + box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); } @font-face { font-family: 'Avenir Next'; @@ -360,16 +360,16 @@ fieldset { top: 0; overflow: hidden; max-width: 75rem; - margin-left: auto; - margin-right: auto; + margin: 0 auto 1rem; background-color: $color_white; color: $color_gray_dark; padding: 0 0.7rem; border-bottom-left-radius: 1rem; border-bottom-right-radius: 1rem; - -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); - -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); - box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + @include shadow(); div { float: left; @@ -584,9 +584,10 @@ fieldset { opacity: 1; background-color: $color_button_background; border-radius: 0.8rem; - -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); - -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); - box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // -webkit-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // -moz-box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + // box-shadow: 2px 2px 3px 1px rgba(0, 0, 0, .75); + @include shadow(); .app_icon { font: normal normal normal 14px/1 FontAwesome; @@ -628,9 +629,11 @@ fieldset { border: 0; border-radius: 0.75rem; background: #fff; - -webkit-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); - -moz-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); - box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); + // -webkit-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); + // -moz-box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); + // box-shadow: 0.5rem 0.5rem 0 0 rgba(50, 50, 50, .75); + + @include shadow(); .titlebar { font-size: 2rem; @@ -704,10 +707,11 @@ fieldset { .actionbar { min-height: 4rem; - margin: .5rem 0 1rem; // 1rem; + margin: -0.5rem 0 1rem; // 1rem; padding: 0.5rem 1rem; background: #23774e; border-radius: 0.5rem; + @include shadow(); .action { display: inline-block; From cb615d865e71af74b6c1dd684ab9dc24fdc9c79d Mon Sep 17 00:00:00 2001 From: Stan Date: Wed, 8 Mar 2017 17:56:56 +0100 Subject: [PATCH 11/60] Auto reload changes --- src/opsoro/server/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/opsoro/server/__init__.py b/src/opsoro/server/__init__.py index c09a651..70150fc 100644 --- a/src/opsoro/server/__init__.py +++ b/src/opsoro/server/__init__.py @@ -58,6 +58,8 @@ def __init__(self): # Create flask instance for webserver self.flaskapp = Flask(__name__) + # self.flaskapp.config['DEBUG'] = True + self.flaskapp.config['TEMPLATES_AUTO_RELOAD'] = True # Translation support self.flaskapp.config.from_pyfile('settings.cfg') From a9da6c1b055b2dde8c0498d2aedab4d0517deb41 Mon Sep 17 00:00:00 2001 From: Stan Date: Wed, 8 Mar 2017 17:57:14 +0100 Subject: [PATCH 12/60] Clean systembar comments --- src/opsoro/server/templates/_systembar.html | 39 +-------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/src/opsoro/server/templates/_systembar.html b/src/opsoro/server/templates/_systembar.html index cce8d7b..262cd35 100644 --- a/src/opsoro/server/templates/_systembar.html +++ b/src/opsoro/server/templates/_systembar.html @@ -1,5 +1,4 @@ From 130e55e4458e102062495ac49f70a78d3afeea0f Mon Sep 17 00:00:00 2001 From: Stan Date: Tue, 14 Mar 2017 13:47:10 +0100 Subject: [PATCH 13/60] Add preference: Startup_app --- src/opsoro/apps/preferences/__init__.py | 110 ++++--------- src/opsoro/apps/preferences/static/app.js | 64 +++++--- .../preferences/templates/preferences.html | 154 ++++++++++++------ src/opsoro/config/preferences.yaml | 24 +-- src/opsoro/preferences.py | 7 +- src/opsoro/server/__init__.py | 6 + src/opsoro/server/static/css/opsoro.css | 33 ++-- src/opsoro/server/static/css/opsoro.min.css | 2 +- src/opsoro/server/static/css/opsoro.scss | 20 ++- 9 files changed, 228 insertions(+), 192 deletions(-) diff --git a/src/opsoro/apps/preferences/__init__.py b/src/opsoro/apps/preferences/__init__.py index 5ae5462..2e195ab 100644 --- a/src/opsoro/apps/preferences/__init__.py +++ b/src/opsoro/apps/preferences/__init__.py @@ -46,80 +46,39 @@ def index(): if request.method == 'POST': # Update preferences request.form.get('file_name_ext', type=str, default=None) - Preferences.set('general', - 'robot_name', - request.form.get('robotName', - type=str, - default=None)) + Preferences.set('general', 'robot_name', request.form.get('robotName', type=str, default=None)) + Preferences.set('general', 'startup_app', request.form.get('startupApp', type=str, default=None)) pass1 = request.form.get('robotPassword', type=str, default=None) - pass2 = request.form.get('robotPasswordConfirm', - type=str, - default=None) + pass2 = request.form.get('robotPasswordConfirm', type=str, default=None) if pass1 is not None and pass1 == pass2: if pass1 != '': - Preferences.set('general', 'password', pass1) + Preferences.set('security', 'password', pass1) # Preferences.set('update', 'branch', request.form.get('updateBranch', type=str, default=None)) # Preferences.set('update', 'auto_update', # request.form.get('updateAuto', type=str, default=None)) - Preferences.set('alive', - 'enabled', - request.form.get('aliveEnabled', - type=bool, - default=False)) - # Preferences.set('alive', 'aliveness', request.form.get('aliveness', type=str, default=None)) - Preferences.set('alive', 'aliveness', 0) - Preferences.set('alive', - 'blink', - request.form.get('aliveBlink', - type=bool, - default=False)) - Preferences.set('alive', - 'gaze', - request.form.get('aliveGaze', - type=bool, - default=False)) - - Preferences.set('audio', - 'master_volume', - request.form.get('volume', type=int)) - Preferences.set('audio', - 'tts_engine', - request.form.get('ttsEngine', - type=str, - default=None)) - Preferences.set( - 'audio', - 'tts_language', - request.form.get('ttsLanguage', type=str, default=None)) - Preferences.set('audio', - 'tts_gender', - request.form.get('ttsGender', - type=str, - default=None)) - - Preferences.set('wireless', - 'ssid', - request.form.get('wirelessSsid', - type=str, - default=None)) - Preferences.set('wireless', - 'channel', - request.form.get('wirelessChannel', type=int)) + Preferences.set('behaviour', 'enabled', request.form.get('aliveEnabled', type=bool, default=False)) + # Preferences.set('behaviour', 'caffeine', request.form.get('caffeine', type=str, default=None)) + Preferences.set('behaviour', 'caffeine', 0) + Preferences.set('behaviour', 'blink', request.form.get('aliveBlink', type=bool, default=False)) + Preferences.set('behaviour', 'gaze', request.form.get('aliveGaze', type=bool, default=False)) + + Preferences.set('audio', 'master_volume', request.form.get('volume', type=int)) + Preferences.set('audio', 'tts_engine', request.form.get('ttsEngine', type=str, default=None)) + Preferences.set('audio', 'tts_language', request.form.get('ttsLanguage', type=str, default=None)) + Preferences.set('audio', 'tts_gender', request.form.get('ttsGender', type=str, default=None)) + + Preferences.set('wireless', 'ssid', request.form.get('wirelessSsid', type=str, default=None)) + Preferences.set('wireless', 'channel', request.form.get('wirelessChannel', type=int)) if request.form.get('wirelessSamePass', None) == 'on': # Set to same password - Preferences.set('wireless', 'password', Preferences.get( - 'general', 'password', 'RobotOpsoro')) + Preferences.set('wireless', 'password', Preferences.get('general', 'password', 'RobotOpsoro')) else: - pass1 = request.form.get('wirelessPassword', - type=str, - default=None) - pass2 = request.form.get('wirelessPasswordConfirm', - type=str, - default=None) + pass1 = request.form.get('wirelessPassword', type=str, default=None) + pass2 = request.form.get('wirelessPasswordConfirm', type=str, default=None) if pass1 is not None and pass1 == pass2: if pass1 != '': Preferences.set('wireless', 'password', pass1) @@ -134,21 +93,20 @@ def index(): # Prepare json string with prefs data data['prefs'] = { 'general': { - 'robotName': - Preferences.get('general', 'robot_name', 'Robot') + 'robotName': Preferences.get('general', 'robot_name', 'Robot'), + 'startupApp': Preferences.get('general', 'startup_app', '') }, 'update': { 'available': Preferences.check_if_update(), - 'branch': Preferences.get('update', 'branch', - Preferences.get_current_branch()), + 'branch': Preferences.get('update', 'branch', Preferences.get_current_branch()), # 'branches': Preferences.get_remote_branches(), 'autoUpdate': Preferences.get('update', 'auto_update', False) }, - 'alive': { - 'enabled': Preferences.get('alive', 'enabled', False), - 'aliveness': Preferences.get('alive', 'aliveness', '0'), - 'blink': Preferences.get('alive', 'blink', True), - 'gaze': Preferences.get('alive', 'gaze', True) + 'behaviour': { + 'enabled': Preferences.get('behaviour', 'enabled', False), + 'caffeine': Preferences.get('behaviour', 'caffeine', '0'), + 'blink': Preferences.get('behaviour', 'blink', True), + 'gaze': Preferences.get('behaviour', 'gaze', True) }, 'audio': { 'volume': Preferences.get('audio', 'master_volume', 66), @@ -157,16 +115,16 @@ def index(): 'ttsGender': Preferences.get('audio', 'tts_gender', 'm') }, 'wireless': { - 'ssid': - Preferences.get('wireless', 'ssid', 'OPSORO' + '_AP'), - 'samePassword': - Preferences.get('general', 'password', 'RobotOpsoro') == - Preferences.get('wireless', 'password', 'RobotOpsoro'), + 'ssid': Preferences.get('wireless', 'ssid', 'OPSORO' + '_bot'), + 'samePassword': Preferences.get('general', 'password', 'opsoro123') == + Preferences.get('wireless', 'password', 'opsoro123'), 'channel': Preferences.get('wireless', 'channel', '1') } } - print_info(data) + data['apps'] = [] + for appi in opsoroapp.apps: + data['apps'].append(str(appi)) return opsoroapp.render_template(config['formatted_name'] + '.html', **data) diff --git a/src/opsoro/apps/preferences/static/app.js b/src/opsoro/apps/preferences/static/app.js index 54f5d60..a1292bf 100644 --- a/src/opsoro/apps/preferences/static/app.js +++ b/src/opsoro/apps/preferences/static/app.js @@ -2,25 +2,26 @@ $(document).ready(function () { var GeneralSettings = function () { var self = this; - self.robotName = ko.observable(""); - self.password = ko.observable(""); - self.passwordConfirm = ko.observable(""); + self.robotName = ko.observable(''); + self.startupApp = ko.observable(''); + self.apps = ['--None--']; + self.apps = self.apps.concat(appsJson); }; var UpdateSettings = function () { var self = this; self.available = ko.observable(false); - self.branch = ko.observable(""); + self.branch = ko.observable(''); self.branches = ko.observable(); self.autoUpdate = ko.observable(false); }; - var AliveSettings = function () { + var BehaviourSettings = function () { var self = this; self.enabled = ko.observable(false); - self.aliveness = ko.observable(0); + self.caffeine = ko.observable(0); self.blink = ko.observable(false); self.gaze = ko.observable(false); }; @@ -29,20 +30,20 @@ $(document).ready(function () { var self = this; self.volume = ko.observable(0); - self.ttsEngine = ko.observable("pico"); - self.ttsLanguage = ko.observable("nl"); - self.ttsGender = ko.observable("m"); + self.ttsEngine = ko.observable('pico'); + self.ttsLanguage = ko.observable('nl'); + self.ttsGender = ko.observable('m'); }; var WirelessSettings = function () { var self = this; - self.ssid = ko.observable("OPSORO-bot"); + self.ssid = ko.observable('OPSORO-bot'); - self.password = ko.observable(""); - self.passwordConfirm = ko.observable(""); + self.password = ko.observable(''); + self.passwordConfirm = ko.observable(''); self.samePassword = ko.observable(true); - self.channel = ko.observable("0"); + self.channel = ko.observable('0'); self.settingsChanged = ko.observable(false); var changed_fn = function () { @@ -55,40 +56,57 @@ $(document).ready(function () { self.settingsChanged(false); }; + var SecuritySettings = function () { + var self = this; + + self.password = ko.observable(''); + self.passwordConfirm = ko.observable(''); + }; + var SettingsModel = function () { var self = this; self.general = ko.observable(new GeneralSettings()); self.update = ko.observable(new UpdateSettings()); - self.alive = ko.observable(new AliveSettings()); + + self.behaviour = ko.observable(new BehaviourSettings()); + self.audio = ko.observable(new AudioSettings()); + self.wireless = ko.observable(new WirelessSettings()); + + self.security = ko.observable(new SecuritySettings()); }; var viewmodel = new SettingsModel(); ko.applyBindings(viewmodel); - viewmodel.general().robotName(prefsJson.general.robotName || "Ono"); + viewmodel.general().robotName(prefsJson.general.robotName || 'robot'); + viewmodel.general().startupApp(prefsJson.general.startupApp || ''); + // viewmodel.general().apps = appsJson; viewmodel.update().available(prefsJson.update.available || false); viewmodel.update().branches(prefsJson.update.branches || undefined); viewmodel.update().autoUpdate(prefsJson.update.autoUpdate || false); viewmodel.update().branch(prefsJson.update.branch || ''); - viewmodel.alive().enabled(prefsJson.alive.enabled || false); - viewmodel.alive().aliveness(prefsJson.alive.aliveness || 0); - viewmodel.alive().blink(prefsJson.alive.blink || false); - viewmodel.alive().gaze(prefsJson.alive.gaze || false); + viewmodel.behaviour().enabled(prefsJson.behaviour.enabled || false); + viewmodel.behaviour().caffeine(prefsJson.behaviour.caffeine || 0); + viewmodel.behaviour().blink(prefsJson.behaviour.blink || false); + viewmodel.behaviour().gaze(prefsJson.behaviour.gaze || false); viewmodel.audio().volume(prefsJson.audio.volume || 50); - viewmodel.audio().ttsEngine(prefsJson.audio.ttsEngine || "pico"); - viewmodel.audio().ttsLanguage(prefsJson.audio.ttsLanguage || "nl"); - viewmodel.audio().ttsGender(prefsJson.audio.ttsGender || "m"); + viewmodel.audio().ttsEngine(prefsJson.audio.ttsEngine || 'pico'); + viewmodel.audio().ttsLanguage(prefsJson.audio.ttsLanguage || 'nl'); + viewmodel.audio().ttsGender(prefsJson.audio.ttsGender || 'm'); - viewmodel.wireless().ssid(prefsJson.wireless.ssid || "OPSORO-bot"); + viewmodel.wireless().ssid(prefsJson.wireless.ssid || 'OPSORO-bot'); viewmodel.wireless().samePassword(prefsJson.wireless.samePassword || true); viewmodel.wireless().channel(prefsJson.wireless.channel || 6); viewmodel.wireless().settingsChanged(false); + console.log('loaded'); + console.log(viewmodel.general().apps); + // Fix foundation not updating sliders $('.tab-title').click(function(){ $(document).foundation('slider', 'reflow'); diff --git a/src/opsoro/apps/preferences/templates/preferences.html b/src/opsoro/apps/preferences/templates/preferences.html index 141d551..6ebffce 100644 --- a/src/opsoro/apps/preferences/templates/preferences.html +++ b/src/opsoro/apps/preferences/templates/preferences.html @@ -8,21 +8,43 @@ {% block app_content %} -
+ -
+
@@ -35,7 +57,7 @@
-
+
@@ -43,26 +65,20 @@ A valid name is required
+
-
- -
-
- -
-
-
-
- +
+
- - The password did not match - - Note: - Passwords is stored in a plain text file and are - not secure! Do not use this password for anything else! - +
@@ -73,7 +89,7 @@ Update
-
+
@@ -113,7 +129,7 @@ Audio
-
+
@@ -129,7 +145,7 @@
-
+
@@ -140,7 +156,7 @@
-
+
@@ -153,7 +169,7 @@
-
+
@@ -168,17 +184,17 @@
-
+
- Aliveness + Behaviour
- +
- - + +
@@ -186,28 +202,28 @@
- +
- - + +
@@ -215,10 +231,10 @@
- +
- - + +
@@ -239,7 +255,7 @@ Wireless settings have been changed. They will take effect the next time the robot is started.
-
+
@@ -248,7 +264,7 @@
-
+
@@ -256,7 +272,7 @@
-
+
@@ -271,7 +287,7 @@
-
+
@@ -292,6 +308,43 @@
+ +
+
+ + + Password + +
+
+ +
+
+ +
+
+
+
+ +
+
+ + The password did not match +
+
+
+
+ + Note: + Passwords are stored in a plain text file and are + not secure! Do not use this password for anything else! + +
+
+
+ +
+
@@ -300,6 +353,7 @@ {% endblock %} diff --git a/src/opsoro/config/preferences.yaml b/src/opsoro/config/preferences.yaml index 9f77780..45513dd 100644 --- a/src/opsoro/config/preferences.yaml +++ b/src/opsoro/config/preferences.yaml @@ -1,17 +1,19 @@ -general: - robot_name: robot - password: opsoro123 -alive: - enabled: false - aliveness: 30 - blink: true - gaze: true audio: master_volume: 60 tts_engine: espeak - tts_language: en tts_gender: f -wireless: - ssid: OPSORO-bot + tts_language: en +behaviour: + blink: false + caffeine: 0 + enabled: false + gaze: false +general: + robot_name: robot + startup_app: --None-- +security: password: opsoro123 +wireless: channel: 6 + password: RobotOpsoro + ssid: OPSORO-bot diff --git a/src/opsoro/preferences.py b/src/opsoro/preferences.py index e2bd9fa..18db55e 100644 --- a/src/opsoro/preferences.py +++ b/src/opsoro/preferences.py @@ -103,8 +103,7 @@ def check_if_update(self): # Update local git data self.git.fetch() except: - print_warning( - "Failed to fetch, is there a git repo setup and do you have internet?") + print_warning("Failed to fetch, is there a git repo setup and do you have internet?") return False # Retrieve git remote <-> local difference status status = self.git.status() @@ -179,9 +178,7 @@ def save_prefs(self): """ try: with open(get_path("config/preferences.yaml"), "w") as f: - f.write( - yaml.dump( - self.data, default_flow_style=False, Dumper=Dumper)) + f.write(yaml.dump(self.data, default_flow_style=False, Dumper=Dumper)) except IOError: print_warning("Could not save config/preferences.yaml") diff --git a/src/opsoro/server/__init__.py b/src/opsoro/server/__init__.py index 70150fc..615c4f8 100644 --- a/src/opsoro/server/__init__.py +++ b/src/opsoro/server/__init__.py @@ -284,6 +284,12 @@ def update_users(conn): tornado_app = tornado.web.Application(app_socketrouter.urls + self.user_socketrouter.urls + [(r".*", tornado.web.FallbackHandler, {"fallback": flaskwsgi})]) tornado_app.listen(80) + # Start default app + startup_app = Preferences.get('general', 'startup_app', None) + if startup_app in self.apps: + self.request_handler.page_openapp(startup_app) + + # SSL security # http_server = tornado.httpserver.HTTPServer(tornado_app, ssl_options={ # "certfile": "/etc/ssl/certs/server.crt", # "keyfile": "/etc/ssl/private/server.key", diff --git a/src/opsoro/server/static/css/opsoro.css b/src/opsoro/server/static/css/opsoro.css index a5dc49a..d5896d8 100644 --- a/src/opsoro/server/static/css/opsoro.css +++ b/src/opsoro/server/static/css/opsoro.css @@ -118,6 +118,8 @@ fieldset { .tabs { width: 100% !important; max-width: 100% !important; } + .tabs .tab-title > a { + padding: 1rem 1rem; } .tabs-content .content { padding-top: 0; } @@ -252,13 +254,13 @@ fieldset { padding: 0 0.7rem; border-bottom-left-radius: 1rem; border-bottom-right-radius: 1rem; - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); } #header_play div { float: left; padding: 0; } - #header_play i { + #header_play .icon { float: left; } #header_play p { float: left; @@ -275,20 +277,20 @@ fieldset { margin: 0; } #header_play ul li { margin: 0; } - #header_play i { + #header_play .icon { margin: 0.5rem 0.5rem 0 0; font-size: 3.3rem; } #header_play #status { text-transform: uppercase; font-weight: bold; } - #header_play #comment i { + #header_play #comment .icon { margin: 0.2rem 0.2rem 0 0; font-size: 1.1rem; } #header_play a { margin: 0; padding: 0; color: #27292a; } - #header_play a i { + #header_play a .icon { margin: 1rem 0 0.5rem 1rem; font-size: 2.3rem; } #header_play .status { @@ -410,9 +412,9 @@ fieldset { opacity: 1; background-color: #FFF; border-radius: 0.8rem; - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); } .apps .app_container .app_button .app_icon { font: normal normal normal 14px/1 FontAwesome; font-size: 5rem; @@ -445,9 +447,9 @@ fieldset { border: 0; border-radius: 0.75rem; background: #fff; - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); + box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.8); } .reveal-modal .titlebar { font-size: 2rem; font-weight: bold; @@ -506,10 +508,7 @@ fieldset { margin: -0.5rem 0 1rem; padding: 0.5rem 1rem; background: #23774e; - border-radius: 0.5rem; - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); - box-shadow: 3px 3px 2px rgba(0, 0, 0, 0.5); } + border-radius: 0.5rem; } .actionbar .action { display: inline-block; min-width: 3rem; diff --git a/src/opsoro/server/static/css/opsoro.min.css b/src/opsoro/server/static/css/opsoro.min.css index 9efeb9f..7c97eec 100644 --- a/src/opsoro/server/static/css/opsoro.min.css +++ b/src/opsoro/server/static/css/opsoro.min.css @@ -1 +1 @@ -@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Regular.ttf") format("truetype");font-style:normal;font-weight:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-DemiBold.ttf") format("truetype");font-weight:500;font-style:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Bold.ttf") format("truetype");font-weight:700;font-style:normal}body{height:auto;color:#27292a;background:#F2F2F2;background-image:url("../images/background/bg_tiled_dark.png");font-family:'Avenir Next' !important;font-size:1.1rem}article,div,h1,h2,h3,h4,h5,h6,p,section,span{font-family:'Avenir Next'}hr{margin:10000}a{outline:0}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}footer{height:4rem}footer .container{margin-top:0}footer img{display:block;width:8rem;margin:0.5rem auto;opacity:0.75}h1{font-size:3rem;text-align:center;font-weight:bold;color:#6e00ff}h2{margin:0.5rem 0;font-size:2rem;font-weight:bold;color:#27292a}h3{font-size:1.2rem;font-weight:bold}img{margin-left:auto;margin-right:auto;padding:0}article{padding:1rem;margin:0 auto;text-align:justify}p{padding:0 1rem;margin:0.5rem 0}a{text-decoration:none;font-weight:bold;color:#27292a;outline:medium none !important}a:active,a:focus,a:hover{text-decoration:none;color:#15e678 !important}a:visited{text-decoration:none}fieldset legend{background-color:transparent}fieldset{margin-top:0 !important}.tabs{width:100% !important;max-width:100% !important}.tabs-content .content{padding-top:0}.nav{width:100%}.nav img{float:left}.nav ul{float:right}.nav ul li{float:left;margin:1rem;list-style-type:none}.nav ul li a,.nav ul li a:visited{font-size:1rem;font-weight:bold;text-decoration:none;text-transform:uppercase;color:#fff}.row{max-width:75rem}.color_green{color:#15e678}.color_blue{color:#36c9ff}.color_orange{color:#ffaf19}.color_red{color:#ff517e}.color_purple{color:#6e00ff}.color_yellow{color:#fff000}.color_gray_light{color:#F2F2F2;background-color:#27292a}.color_gray_light h1{color:#F2F2F2}.color_gray_light a{color:#F2F2F2}.color_gray_dark{color:#27292a}.color_white{color:#fff}.text_caps{text-transform:uppercase}.text_center{text-align:center;vertical-align:middle}.box_center{float:none;margin-left:auto;margin-right:auto}.side_right{float:right;text-align:right}.full_width{max-width:100%}.full_width *{max-width:75rem;margin-left:auto;margin-right:auto}.nopadding{padding:0}.circle{-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%}.rectangle{-webkit-border-radius:1rem;-moz-border-radius:1rem;border-radius:1rem}.btn{font-size:1rem;padding:0.5rem 2rem;height:2.3125rem;background-color:#6e00ff;color:#F2F2F2;font-weight:bold}.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:none;margin-left:auto;margin-right:auto}.columns+.columns:last-child{float:left}#header_play{position:relative;top:0;overflow:hidden;max-width:75rem;margin:0 auto 1rem;background-color:#fff;color:#27292a;padding:0 0.7rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}#header_play div{float:left;padding:0}#header_play i{float:left}#header_play p{float:left;padding:0}#header_play .side_right{float:right}#header_play .text_center{float:none;margin-left:auto;margin-right:auto;width:10rem}#header_play ul{text-align:center;margin:0}#header_play ul li{margin:0}#header_play i{margin:0.5rem 0.5rem 0 0;font-size:3.3rem}#header_play #status{text-transform:uppercase;font-weight:bold}#header_play #comment i{margin:0.2rem 0.2rem 0 0;font-size:1.1rem}#header_play a{margin:0;padding:0;color:#27292a}#header_play a i{margin:1rem 0 0.5rem 1rem;font-size:2.3rem}#header_play .status{margin:0.5rem 0}.sidebar_left,.sidebar_right{position:fixed;z-index:8;top:50px;bottom:0;left:0;display:block;overflow:visible;overflow:auto;max-width:13rem;padding:1rem;color:#000;background-color:rgba(255,255,255,0.5);-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.sidebar_left:empty,.sidebar_right:empty{display:none}.sidebar_right{right:0;left:auto}.container{position:relative;max-width:75rem;margin-top:0.5rem;margin-right:auto;margin-left:auto;padding:0}.announcements{position:fixed;z-index:10;right:0;bottom:0;left:0;display:block;width:100%;text-align:center}.announcement{position:relative;max-width:40rem;margin-top:1rem;margin-right:auto;margin-left:auto;padding:0.75rem;text-align:center;-webkit-border-top-left-radius:0.8rem;-moz-border-radius-topleft:0.8rem;border-top-left-radius:0.8rem;-webkit-border-top-right-radius:0.8rem;-moz-border-radius-topright:0.8rem;border-top-right-radius:0.8rem;color:#fff;background-color:#333;-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.announcement .btn{font-size:2rem;position:absolute;top:0;right:0;display:block;width:2.75rem;height:2.75rem;padding:0;color:#fff;border-style:none;background-color:transparent}.announcement .btn:active,.announcement .btn:hover{font-size:2.1rem;color:#fff;border-style:none;background-color:transparent}.apps{max-width:100%;margin-right:auto;margin-left:auto;padding:0}.apps .app_container{margin:0 auto 1rem}.apps .app_container a{float:none;color:#27292a}.apps .app_container a:hover{text-decoration:none;color:#27292a !important}.apps .app_container a:hover .app_icon{font-size:5.5rem;margin:1.75rem auto}.apps .app_container .app_button{position:relative;display:block;overflow:hidden;width:9rem;height:9rem;margin:0.5rem auto;text-align:center;vertical-align:middle;opacity:1;background-color:#fff;border-radius:0.8rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.apps .app_container .app_button .app_icon{font:normal normal normal 14px/1 FontAwesome;font-size:5rem;display:inline-block;width:100%;margin:2rem auto}.apps .app_container .app_button .app_banner{position:absolute;display:block;bottom:0;left:0;width:100%;height:1rem}.apps .app_container .app_label{font-size:1.2rem;font-weight:normal;overflow:hidden;width:100%;text-align:center}.reveal-modal{position:absolute;top:1rem;right:1rem;left:1rem;margin-right:auto;margin-left:auto;padding:0;color:#4d4d4d;border:0;border-radius:0.75rem;background:#fff;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.reveal-modal .titlebar{font-size:2rem;font-weight:bold;position:relative;padding:0.5rem;text-align:center;color:#fff;border-bottom:0.25rem solid #545454;-webkit-border-top-left-radius:0.5rem;-moz-border-radius-topleft:0.5rem;border-top-left-radius:0.5rem;-webkit-border-top-right-radius:0.5rem;-moz-border-radius-topright:0.5rem;border-top-right-radius:0.5rem;background:#b2afa1}.reveal-modal .titlebar.red{border-bottom:0.25rem solid #79261d;background:#b2382a}.reveal-modal .titlebar.green{border-bottom:0.25rem solid #26791d;background:#38b22a}.reveal-modal .content{padding:1rem}.reveal-modal .close-reveal{font-size:2rem;font-weight:normal;position:absolute;top:1rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .close-reveal:hover{font-size:2.5rem;top:0.75rem;left:0.75rem}.reveal-modal .btnClose{font-size:2rem;font-weight:normal;position:absolute;top:0.5rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .btnClose:hover{font-size:2.5rem;top:0.25rem;left:0.75rem}.float_right{float:right}.actionbar{min-height:4rem;margin:-0.5rem 0 1rem;padding:0.5rem 1rem;background:#23774e;border-radius:0.5rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.5);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.5);box-shadow:3px 3px 2px rgba(0,0,0,0.5)}.actionbar .action{display:inline-block;min-width:3rem;padding:0 0.5rem;text-align:center;color:#fff;-webkit-border-radius:0.25rem;-moz-border-radius:0.25rem;border-radius:0.25rem}.actionbar .action .text{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar .action.active,.actionbar .action:hover{color:#4d4d4d;background:#fff}.actionbar .spacer{display:inline-block;width:2rem}.actionbar .filebox{display:inline-block;overflow:hidden;min-width:7rem;max-width:20rem;white-space:nowrap;text-overflow:ellipsis;color:#fff}.actionbar .filebox .filename{font-weight:bold;text-transform:uppercase}.actionbar .filebox .status{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar:empty{display:none}.contentwrapper *{font:12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important}.fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#F2F2F2;padding:0;margin:0;z-index:9}.fullscreen .contentwrapper{height:calc(100vh - 4rem - 4.15rem)}.fullscreen .console{border-bottom-right-radius:0;border-bottom-left-radius:0}.fullscreen .actionbar{margin:0;border-radius:0}.fullscreen .container{margin:0;padding:0;max-width:100%;width:100%;height:100%}.filebrowser{position:fixed;right:1rem;bottom:3rem;left:1rem}.filebrowser .content{position:absolute;top:4rem;bottom:0;width:100%}.filebrowser .actionbar .actionBarItem{position:relative;float:left;min-width:4rem}.filebrowser .foldercontent{position:absolute;top:4.5rem;bottom:0.5rem;left:0;overflow-x:hidden;overflow-y:scroll;width:100%;padding:0 3rem 3rem}.filebrowser .foldercontent .button{font-size:1.5rem;width:5rem;margin-left:0.5rem;padding:0}.filebrowser .foldercontent .alert{width:2.5rem}.filebrowser .foldercontent .browseritem{width:100%;min-height:2rem;margin:0.1rem;padding:0.2rem;border-radius:0.25rem}.filebrowser .foldercontent .browseritem:hover{background-color:#f2f2f2}.filebrowser .foldercontent .browseritem:hover .browseritemoptions{opacity:1}.filebrowser .foldercontent .browseritem a{margin:0}.filebrowser .foldercontent .browseritem .browseritemname{font-size:1.5rem;font-weight:bold;margin-left:2rem}.filebrowser .foldercontent .browseritem .browseritemoptions{float:right;padding:0.15rem}.filebrowser .foldercontent .browseritem .browseritemoptions{-webkit-transition:opacity 0.1s ease-in-out;-moz-transition:opacity 0.1s ease-in-out;transition:opacity 0.1s ease-in-out;opacity:0}#message_popup .content .buttons{position:relative;text-align:center}#message_popup .content .buttons .button{margin-right:1rem;margin-left:1rem} +@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Regular.ttf") format("truetype");font-style:normal;font-weight:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-DemiBold.ttf") format("truetype");font-weight:500;font-style:normal}@font-face{font-family:'Avenir Next';src:url("../fonts/AvenirNext-Bold.ttf") format("truetype");font-weight:700;font-style:normal}body{height:auto;color:#27292a;background:#F2F2F2;background-image:url("../images/background/bg_tiled_dark.png");font-family:'Avenir Next' !important;font-size:1.1rem}article,div,h1,h2,h3,h4,h5,h6,p,section,span{font-family:'Avenir Next'}hr{margin:10000}a{outline:0}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}footer{height:4rem}footer .container{margin-top:0}footer img{display:block;width:8rem;margin:0.5rem auto;opacity:0.75}h1{font-size:3rem;text-align:center;font-weight:bold;color:#6e00ff}h2{margin:0.5rem 0;font-size:2rem;font-weight:bold;color:#27292a}h3{font-size:1.2rem;font-weight:bold}img{margin-left:auto;margin-right:auto;padding:0}article{padding:1rem;margin:0 auto;text-align:justify}p{padding:0 1rem;margin:0.5rem 0}a{text-decoration:none;font-weight:bold;color:#27292a;outline:medium none !important}a:active,a:focus,a:hover{text-decoration:none;color:#15e678 !important}a:visited{text-decoration:none}fieldset legend{background-color:transparent}fieldset{margin-top:0 !important}.tabs{width:100% !important;max-width:100% !important}.tabs .tab-title>a{padding:1rem 1rem}.tabs-content .content{padding-top:0}.nav{width:100%}.nav img{float:left}.nav ul{float:right}.nav ul li{float:left;margin:1rem;list-style-type:none}.nav ul li a,.nav ul li a:visited{font-size:1rem;font-weight:bold;text-decoration:none;text-transform:uppercase;color:#fff}.row{max-width:75rem}.color_green{color:#15e678}.color_blue{color:#36c9ff}.color_orange{color:#ffaf19}.color_red{color:#ff517e}.color_purple{color:#6e00ff}.color_yellow{color:#fff000}.color_gray_light{color:#F2F2F2;background-color:#27292a}.color_gray_light h1{color:#F2F2F2}.color_gray_light a{color:#F2F2F2}.color_gray_dark{color:#27292a}.color_white{color:#fff}.text_caps{text-transform:uppercase}.text_center{text-align:center;vertical-align:middle}.box_center{float:none;margin-left:auto;margin-right:auto}.side_right{float:right;text-align:right}.full_width{max-width:100%}.full_width *{max-width:75rem;margin-left:auto;margin-right:auto}.nopadding{padding:0}.circle{-webkit-border-radius:50%;-moz-border-radius:50%;border-radius:50%}.rectangle{-webkit-border-radius:1rem;-moz-border-radius:1rem;border-radius:1rem}.btn{font-size:1rem;padding:0.5rem 2rem;height:2.3125rem;background-color:#6e00ff;color:#F2F2F2;font-weight:bold}.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:none;margin-left:auto;margin-right:auto}.columns+.columns:last-child{float:left}#header_play{position:relative;top:0;overflow:hidden;max-width:75rem;margin:0 auto 1rem;background-color:#fff;color:#27292a;padding:0 0.7rem;border-bottom-left-radius:1rem;border-bottom-right-radius:1rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.8);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.8);box-shadow:3px 3px 2px rgba(0,0,0,0.8)}#header_play div{float:left;padding:0}#header_play .icon{float:left}#header_play p{float:left;padding:0}#header_play .side_right{float:right}#header_play .text_center{float:none;margin-left:auto;margin-right:auto;width:10rem}#header_play ul{text-align:center;margin:0}#header_play ul li{margin:0}#header_play .icon{margin:0.5rem 0.5rem 0 0;font-size:3.3rem}#header_play #status{text-transform:uppercase;font-weight:bold}#header_play #comment .icon{margin:0.2rem 0.2rem 0 0;font-size:1.1rem}#header_play a{margin:0;padding:0;color:#27292a}#header_play a .icon{margin:1rem 0 0.5rem 1rem;font-size:2.3rem}#header_play .status{margin:0.5rem 0}.sidebar_left,.sidebar_right{position:fixed;z-index:8;top:50px;bottom:0;left:0;display:block;overflow:visible;overflow:auto;max-width:13rem;padding:1rem;color:#000;background-color:rgba(255,255,255,0.5);-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.sidebar_left:empty,.sidebar_right:empty{display:none}.sidebar_right{right:0;left:auto}.container{position:relative;max-width:75rem;margin-top:0.5rem;margin-right:auto;margin-left:auto;padding:0}.announcements{position:fixed;z-index:10;right:0;bottom:0;left:0;display:block;width:100%;text-align:center}.announcement{position:relative;max-width:40rem;margin-top:1rem;margin-right:auto;margin-left:auto;padding:0.75rem;text-align:center;-webkit-border-top-left-radius:0.8rem;-moz-border-radius-topleft:0.8rem;border-top-left-radius:0.8rem;-webkit-border-top-right-radius:0.8rem;-moz-border-radius-topright:0.8rem;border-top-right-radius:0.8rem;color:#fff;background-color:#333;-webkit-box-shadow:0 0 3px 1px;-moz-box-shadow:0 0 3px 1px;box-shadow:0 0 3px 1px}.announcement .btn{font-size:2rem;position:absolute;top:0;right:0;display:block;width:2.75rem;height:2.75rem;padding:0;color:#fff;border-style:none;background-color:transparent}.announcement .btn:active,.announcement .btn:hover{font-size:2.1rem;color:#fff;border-style:none;background-color:transparent}.apps{max-width:100%;margin-right:auto;margin-left:auto;padding:0}.apps .app_container{margin:0 auto 1rem}.apps .app_container a{float:none;color:#27292a}.apps .app_container a:hover{text-decoration:none;color:#27292a !important}.apps .app_container a:hover .app_icon{font-size:5.5rem;margin:1.75rem auto}.apps .app_container .app_button{position:relative;display:block;overflow:hidden;width:9rem;height:9rem;margin:0.5rem auto;text-align:center;vertical-align:middle;opacity:1;background-color:#fff;border-radius:0.8rem;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.8);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.8);box-shadow:3px 3px 2px rgba(0,0,0,0.8)}.apps .app_container .app_button .app_icon{font:normal normal normal 14px/1 FontAwesome;font-size:5rem;display:inline-block;width:100%;margin:2rem auto}.apps .app_container .app_button .app_banner{position:absolute;display:block;bottom:0;left:0;width:100%;height:1rem}.apps .app_container .app_label{font-size:1.2rem;font-weight:normal;overflow:hidden;width:100%;text-align:center}.reveal-modal{position:absolute;top:1rem;right:1rem;left:1rem;margin-right:auto;margin-left:auto;padding:0;color:#4d4d4d;border:0;border-radius:0.75rem;background:#fff;-webkit-box-shadow:3px 3px 2px rgba(0,0,0,0.8);-moz-box-shadow:3px 3px 2px rgba(0,0,0,0.8);box-shadow:3px 3px 2px rgba(0,0,0,0.8)}.reveal-modal .titlebar{font-size:2rem;font-weight:bold;position:relative;padding:0.5rem;text-align:center;color:#fff;border-bottom:0.25rem solid #545454;-webkit-border-top-left-radius:0.5rem;-moz-border-radius-topleft:0.5rem;border-top-left-radius:0.5rem;-webkit-border-top-right-radius:0.5rem;-moz-border-radius-topright:0.5rem;border-top-right-radius:0.5rem;background:#b2afa1}.reveal-modal .titlebar.red{border-bottom:0.25rem solid #79261d;background:#b2382a}.reveal-modal .titlebar.green{border-bottom:0.25rem solid #26791d;background:#38b22a}.reveal-modal .content{padding:1rem}.reveal-modal .close-reveal{font-size:2rem;font-weight:normal;position:absolute;top:1rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .close-reveal:hover{font-size:2.5rem;top:0.75rem;left:0.75rem}.reveal-modal .btnClose{font-size:2rem;font-weight:normal;position:absolute;top:0.5rem;right:auto;left:1rem;cursor:pointer;color:#fff}.reveal-modal .btnClose:hover{font-size:2.5rem;top:0.25rem;left:0.75rem}.float_right{float:right}.actionbar{min-height:4rem;margin:-0.5rem 0 1rem;padding:0.5rem 1rem;background:#23774e;border-radius:0.5rem}.actionbar .action{display:inline-block;min-width:3rem;padding:0 0.5rem;text-align:center;color:#fff;-webkit-border-radius:0.25rem;-moz-border-radius:0.25rem;border-radius:0.25rem}.actionbar .action .text{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar .action.active,.actionbar .action:hover{color:#4d4d4d;background:#fff}.actionbar .spacer{display:inline-block;width:2rem}.actionbar .filebox{display:inline-block;overflow:hidden;min-width:7rem;max-width:20rem;white-space:nowrap;text-overflow:ellipsis;color:#fff}.actionbar .filebox .filename{font-weight:bold;text-transform:uppercase}.actionbar .filebox .status{font-size:0.75rem;font-weight:bold;text-transform:uppercase}.actionbar:empty{display:none}.contentwrapper *{font:12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important}.fullscreen{position:fixed;top:0;left:0;width:100vw;height:100vh;background-color:#F2F2F2;padding:0;margin:0;z-index:9}.fullscreen .contentwrapper{height:calc(100vh - 4rem - 4.15rem)}.fullscreen .console{border-bottom-right-radius:0;border-bottom-left-radius:0}.fullscreen .actionbar{margin:0;border-radius:0}.fullscreen .container{margin:0;padding:0;max-width:100%;width:100%;height:100%}.filebrowser{position:fixed;right:1rem;bottom:3rem;left:1rem}.filebrowser .content{position:absolute;top:4rem;bottom:0;width:100%}.filebrowser .actionbar .actionBarItem{position:relative;float:left;min-width:4rem}.filebrowser .foldercontent{position:absolute;top:4.5rem;bottom:0.5rem;left:0;overflow-x:hidden;overflow-y:scroll;width:100%;padding:0 3rem 3rem}.filebrowser .foldercontent .button{font-size:1.5rem;width:5rem;margin-left:0.5rem;padding:0}.filebrowser .foldercontent .alert{width:2.5rem}.filebrowser .foldercontent .browseritem{width:100%;min-height:2rem;margin:0.1rem;padding:0.2rem;border-radius:0.25rem}.filebrowser .foldercontent .browseritem:hover{background-color:#f2f2f2}.filebrowser .foldercontent .browseritem:hover .browseritemoptions{opacity:1}.filebrowser .foldercontent .browseritem a{margin:0}.filebrowser .foldercontent .browseritem .browseritemname{font-size:1.5rem;font-weight:bold;margin-left:2rem}.filebrowser .foldercontent .browseritem .browseritemoptions{float:right;padding:0.15rem}.filebrowser .foldercontent .browseritem .browseritemoptions{-webkit-transition:opacity 0.1s ease-in-out;-moz-transition:opacity 0.1s ease-in-out;transition:opacity 0.1s ease-in-out;opacity:0}#message_popup .content .buttons{position:relative;text-align:center}#message_popup .content .buttons .button{margin-right:1rem;margin-left:1rem} diff --git a/src/opsoro/server/static/css/opsoro.scss b/src/opsoro/server/static/css/opsoro.scss index 331eb17..877be53 100644 --- a/src/opsoro/server/static/css/opsoro.scss +++ b/src/opsoro/server/static/css/opsoro.scss @@ -35,9 +35,9 @@ $rounding_medium: 1rem; // box-shadow: 0 0 8px rgba(0, 0, 0, .8); // -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, .8); // -moz-box-shadow: 0 0 8px rgba(0, 0, 0, .8); - -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); - -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); - box-shadow: 3px 3px 2px rgba(0, 0, 0, .5); + -webkit-box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); + -moz-box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); + box-shadow: 3px 3px 2px rgba(0, 0, 0, .8); } @font-face { font-family: 'Avenir Next'; @@ -187,6 +187,9 @@ fieldset { .tab-title { // border-width: 1px; // border-style: solid; + > a { + padding: 1rem 1rem; + } } } // @@ -376,7 +379,7 @@ fieldset { padding: 0; } - i { + .icon { float: left; } @@ -405,14 +408,14 @@ fieldset { margin: 0; // margin-left: 1.5rem; &:last-child { - i { + .icon { // margin-right: 0; } } } } - i { + .icon { margin: 0.5rem 0.5rem 0 0; font-size: 3.3rem; } @@ -423,7 +426,7 @@ fieldset { } #comment { - i { + .icon { margin: 0.2rem 0.2rem 0 0; font-size: 1.1rem; } @@ -438,7 +441,7 @@ fieldset { padding: 0; color: $color_gray_dark; - i { + .icon { margin: 1rem 0 0.5rem 1rem; font-size: 2.3rem; } @@ -711,7 +714,6 @@ fieldset { padding: 0.5rem 1rem; background: #23774e; border-radius: 0.5rem; - @include shadow(); .action { display: inline-block; From d6766b01b661249519a206165aa43fa1e1ca2872 Mon Sep 17 00:00:00 2001 From: Stan Date: Tue, 14 Mar 2017 13:49:03 +0100 Subject: [PATCH 14/60] Icon format update --- src/opsoro/server/templates/_systembar.html | 18 +++++++++--------- .../server/templates/app_not_active.html | 2 +- src/opsoro/server/templates/apps.html | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/opsoro/server/templates/_systembar.html b/src/opsoro/server/templates/_systembar.html index 262cd35..87daea4 100644 --- a/src/opsoro/server/templates/_systembar.html +++ b/src/opsoro/server/templates/_systembar.html @@ -5,9 +5,9 @@ {% block status_icon %} {% if app.active %} - + {% else %} - + {% endif %} {% endblock %} @@ -25,7 +25,7 @@ {% block status_text_comment %} {% if app.active %} - + {{ app.name }} {% else %} @@ -47,34 +47,34 @@
  • - +
  • {% if isuser %}
  • - +
  • - +
  • - +
  • - +
  • {% else %}
  • - +
  • {% endif %} diff --git a/src/opsoro/server/templates/app_not_active.html b/src/opsoro/server/templates/app_not_active.html index 3278ded..aac4ee9 100644 --- a/src/opsoro/server/templates/app_not_active.html +++ b/src/opsoro/server/templates/app_not_active.html @@ -9,7 +9,7 @@
    {% if app.active %} {{ _('Activating it will close the current app:') }} - + {{ app.name }}. {% endif %}

    diff --git a/src/opsoro/server/templates/apps.html b/src/opsoro/server/templates/apps.html index 1bc0a7d..333fd21 100644 --- a/src/opsoro/server/templates/apps.html +++ b/src/opsoro/server/templates/apps.html @@ -59,7 +59,7 @@

    {{ _('No apps available.') }}

    ?
    Doing so will close the current app, - + {{ activeapp.full_name }}.

    From 147c73b64a5c7bbe4eab94251b9186e877bc04ec Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 10:57:38 +0100 Subject: [PATCH 15/60] Social_response update, needs work! --- src/opsoro/apps/social_response/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/opsoro/apps/social_response/__init__.py b/src/opsoro/apps/social_response/__init__.py index a576e21..255d33d 100644 --- a/src/opsoro/apps/social_response/__init__.py +++ b/src/opsoro/apps/social_response/__init__.py @@ -58,17 +58,17 @@ def get_page_data(page_id,fields,access_token): page_id = 'opsoro' # username or id field = 'fan_count' -token = 'EAAaBZCzjU8H8BAFV7KudJn0K1V12CDBHqTIxYu6pVh7cpZAbt1WbZCyZBeSZC472fpPd0ZAkWC1tMrfAY26XnQJUR2rNrMQncQ9OGJlie3dUeQVvabZCwNmGaLL4FGHjZBVTajid16FL5niGWytlwZCiFDgj6yjIsZAAAZD' # Access Token +token = '' # Access Token # ------------------------------------------------------------------------------ # Twitter stuff ---------------------------------------------------------------- # ------------------------------------------------------------------------------ import tweepy #Variables that contains the user credentials to access Twitter API -access_token = '735437381696905216-BboISY7Qcqd1noMDY61zN75CdGT0OSc' -access_token_secret = 'd3A8D1ttrCxYV76pBOB389YqoLB32LiE0RVyoFwuMKUMb' -consumer_key = 'AcdgqgujzF06JF6zWrfwFeUfF' -consumer_secret = 'ss0wVcBTFAT6nR6hXrqyyOcFOhpa2sNW4cIap9JOoepcch93ky' +access_token = '' +access_token_secret = '' +consumer_key = '' +consumer_secret = '' twitterWords = ['#opsoro'] @@ -78,7 +78,7 @@ def get_page_data(page_id,fields,access_token): #override tweepy.StreamListener to add logic to on_status class MyStreamListener(tweepy.StreamListener): def on_status(self, status): - print(status.text) + # print(status.text) # Go_Crazy(text=status.text, twitter=True) txt = status.text for tword in twitterWords: From 1da018a452b110e0e86b0e15971789c8d50ccb58 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 11:34:07 +0100 Subject: [PATCH 16/60] Preferences/update restructuring --- src/opsoro/apps/preferences/__init__.py | 37 +++--- src/opsoro/preferences.py | 96 --------------- src/opsoro/updater.py | 156 ++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 114 deletions(-) create mode 100644 src/opsoro/updater.py diff --git a/src/opsoro/apps/preferences/__init__.py b/src/opsoro/apps/preferences/__init__.py index 2e195ab..dc17bd7 100644 --- a/src/opsoro/apps/preferences/__init__.py +++ b/src/opsoro/apps/preferences/__init__.py @@ -4,6 +4,7 @@ from opsoro.robot import Robot # from opsoro.hardware import Hardware from opsoro.preferences import Preferences +from opsoro.updater import Updater from flask import Blueprint, render_template, request, redirect, url_for, flash @@ -93,32 +94,32 @@ def index(): # Prepare json string with prefs data data['prefs'] = { 'general': { - 'robotName': Preferences.get('general', 'robot_name', 'Robot'), - 'startupApp': Preferences.get('general', 'startup_app', '') + 'robotName': Preferences.get('general', 'robot_name', 'Robot'), + 'startupApp': Preferences.get('general', 'startup_app', '') }, 'update': { - 'available': Preferences.check_if_update(), - 'branch': Preferences.get('update', 'branch', Preferences.get_current_branch()), - # 'branches': Preferences.get_remote_branches(), - 'autoUpdate': Preferences.get('update', 'auto_update', False) + 'available': Updater.is_update_available(), + 'branch': Preferences.get('update', 'branch', Updater.get_current_branch()), + # 'branches': Preferences.get_remote_branches(), + 'autoUpdate': Preferences.get('update', 'auto_update', False) }, 'behaviour': { - 'enabled': Preferences.get('behaviour', 'enabled', False), - 'caffeine': Preferences.get('behaviour', 'caffeine', '0'), - 'blink': Preferences.get('behaviour', 'blink', True), - 'gaze': Preferences.get('behaviour', 'gaze', True) + 'enabled': Preferences.get('behaviour', 'enabled', False), + 'caffeine': Preferences.get('behaviour', 'caffeine', '0'), + 'blink': Preferences.get('behaviour', 'blink', True), + 'gaze': Preferences.get('behaviour', 'gaze', True) }, 'audio': { - 'volume': Preferences.get('audio', 'master_volume', 66), - 'ttsEngine': Preferences.get('audio', 'tts_engine', 'pico'), - 'ttsLanguage': Preferences.get('audio', 'tts_language', 'nl'), - 'ttsGender': Preferences.get('audio', 'tts_gender', 'm') + 'volume': Preferences.get('audio', 'master_volume', 66), + 'ttsEngine': Preferences.get('audio', 'tts_engine', 'pico'), + 'ttsLanguage': Preferences.get('audio', 'tts_language', 'nl'), + 'ttsGender': Preferences.get('audio', 'tts_gender', 'm') }, 'wireless': { - 'ssid': Preferences.get('wireless', 'ssid', 'OPSORO' + '_bot'), + 'ssid': Preferences.get('wireless', 'ssid', 'OPSORO' + '_bot'), 'samePassword': Preferences.get('general', 'password', 'opsoro123') == - Preferences.get('wireless', 'password', 'opsoro123'), - 'channel': Preferences.get('wireless', 'channel', '1') + Preferences.get('wireless', 'password', 'opsoro123'), + 'channel': Preferences.get('wireless', 'channel', '1') } } @@ -131,7 +132,7 @@ def index(): @app_bp.route('/update', methods=['GET', 'POST']) @opsoroapp.app_view def update(): - Preferences.update() + Updater.update() opsoroapp.register_app_blueprint(app_bp) diff --git a/src/opsoro/preferences.py b/src/opsoro/preferences.py index 18db55e..50a2b63 100644 --- a/src/opsoro/preferences.py +++ b/src/opsoro/preferences.py @@ -14,7 +14,6 @@ import os import subprocess import re -from git import Git, Repo from functools import partial import yaml @@ -36,101 +35,6 @@ def __init__(self): """ self.data = {} self.load_prefs() - self.dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), '..', '..')) + '/' - - self.git = None - self.repo = None - try: - self.git = Git(self.dir) - self.repo = Repo(self.dir) - except: - pass - - def get_current_branch(self): - """ - Retrieves the current git branch of the repository. - - :return: current git branch. - :rtype: string - """ - if self.git is None: - return False - try: - return self.git.branch().split()[-1] - except: - print_error( - "Failed to get current branch, is there a git repo setup?") - return "" - - def get_remote_branches(self): - """ - Retrieve all git branches of the repository. - - :return: branches of the repository. - :rtype: list - """ - if self.git is None: - return False - branches = [] - - try: - # Get all remote branches (not only local) - returnvalue = self.git.ls_remote('--heads').split() - - # Strip data - for i in range(len(returnvalue)): - if i % 2 != 0: - # Get only branch name (last value) - branches.append(returnvalue[i].split("/")[-1]) - except: - print_warning( - "Failed to get remote branches, is there a git repo setup and do you have internet?") - pass - - return branches - - def check_if_update(self): - """ - Checks git repository for available changes. - - :return: True if update is available, False if the command failed or no update available. - :rtype: bool - """ - if self.git is None: - return False - try: - # Update local git data - self.git.fetch() - except: - print_warning("Failed to fetch, is there a git repo setup and do you have internet?") - return False - # Retrieve git remote <-> local difference status - status = self.git.status() - # easy check to see if local is behind - if status.find('behind') > 0: - return True - return False - - def update(self): - """ - Creates a update file flag and restarts the service. - """ - if self.git is None: - return False - # Create file to let deamon know it has to update before starting the server - file = open(self.dir + 'update.var', 'w+') - - # restart service - command = ['/usr/sbin/service', 'opsoro', 'restart'] - #shell=FALSE for sudo to work. - subprocess.call(command, shell=False) - - python = sys.executable - os.execl(python, python, *sys.argv) - - # # Reboot system used for user development server run - # os.system('/sbin/shutdown -r now') def load_prefs(self): """ diff --git a/src/opsoro/updater.py b/src/opsoro/updater.py new file mode 100644 index 0000000..f1afd6d --- /dev/null +++ b/src/opsoro/updater.py @@ -0,0 +1,156 @@ +""" +This module defines the interface for updating the robot. + +.. autoclass:: _Updater + :members: + :undoc-members: + :show-inheritance: +""" + +from git import Git, Repo +import os + +from opsoro.console_msg import * + + +class _Updater(object): + def __init__(self): + self.dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) + '/' + + self.git = None + self.repo = None + try: + self.git = Git(self.dir) + self.repo = Repo(self.dir) + except Exception as e: + print_warning('Git repo error' + str(e)) + pass + + def get_current_branch(self): + """ + Retrieves the current git branch of the repository. + + :return: current git branch. + :rtype: string + """ + if self.git is None: + return False + try: + return self.git.branch().split()[-1] + except Exception as e: + print_error("Failed to get current branch, is there a git repo setup?" + str(e)) + return "" + + def get_remote_branches(self): + """ + Retrieve all git branches of the repository. + + :return: branches of the repository. + :rtype: list + """ + if self.git is None: + return False + branches = [] + + try: + # Get all remote branches (not only local) + returnvalue = self.git.ls_remote('--heads').split() + + # Strip data + for i in range(len(returnvalue)): + if i % 2 != 0: + # Get only branch name (last value) + branches.append(returnvalue[i].split("/")[-1]) + except Exception as e: + print_warning("Failed to get remote branches, is there a git repo setup and do you have internet?" + str(e)) + pass + + return branches + + def is_update_available(self): + """ + Checks git repository for available changes. + + :return: True if update is available, False if the command failed or no update available. + :rtype: bool + """ + if self.git is None: + return False + try: + # Update local git data + self.git.fetch() + except Exception as e: + print_error('Failed to fetch: ' + str(e)) + return False + # Retrieve git remote <-> local difference status + status = self.git.status() + # easy check to see if local is behind + if status.find('behind') > 0: + return True + return False + + def update(self): + """ + Updates the opsoro software thru git + """ + if self.git is None: + return False + # Create file to let deamon know it has to update before starting the server + # file = open(self.dir + 'update.var', 'w+') + + backup_dir = '/home/pi/OPSORO/backup/' + + print('Updating...') + if os.path.exists(backup_dir): + # remove previous backup + try: + shutil.rmtree(backup_dir) + except Exception as e: + print_error('Remove backup failed: ' + str(e)) + pass + + try: + shutil.copytree(basedir, backup_dir) + except Exception as e: + print_error('Backup copy failed: ' + str(e)) + pass + + # Link git & update + try: + g = Git(git_dir) + g.fetch('--all') + g.reset('--hard', 'origin/' + g.branch().split()[-1]) + # g.pull() + except Exception as e: + print_error('Git failed to update: ' + str(e)) + pass + + # Set script executable for deamon + try: + st = os.stat(os.path.join(basedir, 'run')) + os.chmod( + os.path.join(basedir, 'run'), st.st_mode | stat.S_IXUSR | + stat.S_IXGRP | stat.S_IXOTH) + except Exception as e: + print_error('Exec state set failed: ' + str(e)) + pass + + # Clear update var file + os.remove(os.path.join(basedir, 'update.var')) + + # restart service + command = ['/usr/sbin/service', 'opsoro', 'restart'] + #shell=FALSE for sudo to work. + subprocess.call(command, shell=False) + + + + # python = sys.executable + # os.execl(python, python, *sys.argv) + + + # # Reboot system used for user development server run + # os.system('/sbin/shutdown -r now') + + +Updater = _Updater() From f8c4218cf67aa02228353e26b2aaded09a27dc2d Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 12:14:24 +0100 Subject: [PATCH 17/60] Update update --- src/opsoro/updater.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/opsoro/updater.py b/src/opsoro/updater.py index f1afd6d..e07f222 100644 --- a/src/opsoro/updater.py +++ b/src/opsoro/updater.py @@ -7,8 +7,18 @@ :show-inheritance: """ +from __future__ import division +from __future__ import with_statement + +import sys +import re +from functools import partial + from git import Git, Repo import os +import subprocess +import shutil +import stat from opsoro.console_msg import * @@ -36,7 +46,7 @@ def get_current_branch(self): if self.git is None: return False try: - return self.git.branch().split()[-1] + return str(self.repo.active_branch).split()[-1] except Exception as e: print_error("Failed to get current branch, is there a git repo setup?" + str(e)) return "" From 57591f993ab1c53a0fcc775cba3c8c4c4b525f4f Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 13:27:10 +0100 Subject: [PATCH 18/60] Updater bugfix/test --- src/opsoro/updater.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/opsoro/updater.py b/src/opsoro/updater.py index e07f222..d3a1f1a 100644 --- a/src/opsoro/updater.py +++ b/src/opsoro/updater.py @@ -120,14 +120,14 @@ def update(self): pass try: - shutil.copytree(basedir, backup_dir) + shutil.copytree(self.dir, backup_dir) except Exception as e: print_error('Backup copy failed: ' + str(e)) pass # Link git & update try: - g = Git(git_dir) + g = Git(self.dir) g.fetch('--all') g.reset('--hard', 'origin/' + g.branch().split()[-1]) # g.pull() @@ -137,16 +137,16 @@ def update(self): # Set script executable for deamon try: - st = os.stat(os.path.join(basedir, 'run')) + st = os.stat(os.path.join(self.dir, 'run')) os.chmod( - os.path.join(basedir, 'run'), st.st_mode | stat.S_IXUSR | + os.path.join(self.dir, 'run'), st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) except Exception as e: print_error('Exec state set failed: ' + str(e)) pass # Clear update var file - os.remove(os.path.join(basedir, 'update.var')) + # os.remove(os.path.join(self.dir, 'update.var')) # restart service command = ['/usr/sbin/service', 'opsoro', 'restart'] From c2c06a7aa2657b1a4871654da71c484acdb40b5d Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 13:31:05 +0100 Subject: [PATCH 19/60] Updater bugfix/test --- src/opsoro/apps/preferences/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opsoro/apps/preferences/__init__.py b/src/opsoro/apps/preferences/__init__.py index dc17bd7..dd398f0 100644 --- a/src/opsoro/apps/preferences/__init__.py +++ b/src/opsoro/apps/preferences/__init__.py @@ -133,6 +133,7 @@ def index(): @opsoroapp.app_view def update(): Updater.update() + return redirect("/") opsoroapp.register_app_blueprint(app_bp) From cd3bd41c1c2e40051c0234cece8df3ceb3e9170f Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 13:34:31 +0100 Subject: [PATCH 20/60] Wrong page redirect --- src/opsoro/server/request_handlers/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/opsoro/server/request_handlers/__init__.py b/src/opsoro/server/request_handlers/__init__.py index 1046b2e..2e6edd7 100644 --- a/src/opsoro/server/request_handlers/__init__.py +++ b/src/opsoro/server/request_handlers/__init__.py @@ -334,7 +334,8 @@ def page_virtual(self): def show_errormessage(self, error): print_error(error) - # return redirect("/") + if error.code == 404: + return redirect("/") return "" def inject_opsoro_vars(self): From 7c380ff0fb6ae5f0221e561602096e7adb30b4c8 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 13:35:16 +0100 Subject: [PATCH 21/60] Updater changes --- run | 96 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/run b/run index e0f8ffb..cdbe1bb 100755 --- a/run +++ b/run @@ -4,9 +4,9 @@ import os import sys import os.path -import shutil -import stat -import subprocess +# import shutil +# import stat +# import subprocess from git import Git, Repo @@ -18,53 +18,53 @@ sys.path.insert(0, os.path.join(basedir, "src")) # ---------------------------------------------------------------------- # UPDATER # ---------------------------------------------------------------------- -git_dir = os.path.abspath(basedir) + '/' -backup_dir = '/home/pi/OPSORO/backup/' +# git_dir = os.path.abspath(basedir) + '/' +# backup_dir = '/home/pi/OPSORO/backup/' # Check if update is needed -if os.path.isfile(os.path.join(basedir, 'update.var')): - print('Updating...') - if os.path.exists(backup_dir): - # remove previous backup - try: - shutil.rmtree(backup_dir) - except Exception as e: - print('Remove backup failed: ', str(e)) - pass - - try: - shutil.copytree(basedir, backup_dir) - except Exception as e: - print('Backup copy failed: ', str(e)) - pass - - # Link git & update - try: - g = Git(git_dir) - g.fetch('--all') - g.reset('--hard', 'origin/' + g.branch().split()[-1]) - # g.pull() - except Exception as e: - print('Git failed to update: ', str(e)) - pass - - # Set script executable for deamon - try: - st = os.stat(os.path.join(basedir, 'run')) - os.chmod( - os.path.join(basedir, 'run'), st.st_mode | stat.S_IXUSR | - stat.S_IXGRP | stat.S_IXOTH) - except Exception as e: - print('Exec state set failed: ', str(e)) - pass - - # Clear update var file - os.remove(os.path.join(basedir, 'update.var')) - - # restart service - command = ['/usr/sbin/service', 'opsoro', 'restart'] - #shell=FALSE for sudo to work. - subprocess.call(command, shell=False) +# if os.path.isfile(os.path.join(basedir, 'update.var')): + # print('Updating...') + # if os.path.exists(backup_dir): + # # remove previous backup + # try: + # shutil.rmtree(backup_dir) + # except Exception as e: + # print('Remove backup failed: ', str(e)) + # pass + # + # try: + # shutil.copytree(basedir, backup_dir) + # except Exception as e: + # print('Backup copy failed: ', str(e)) + # pass + # + # # Link git & update + # try: + # g = Git(git_dir) + # g.fetch('--all') + # g.reset('--hard', 'origin/' + g.branch().split()[-1]) + # # g.pull() + # except Exception as e: + # print('Git failed to update: ', str(e)) + # pass + # + # # Set script executable for deamon + # try: + # st = os.stat(os.path.join(basedir, 'run')) + # os.chmod( + # os.path.join(basedir, 'run'), st.st_mode | stat.S_IXUSR | + # stat.S_IXGRP | stat.S_IXOTH) + # except Exception as e: + # print('Exec state set failed: ', str(e)) + # pass + # + # # Clear update var file + # os.remove(os.path.join(basedir, 'update.var')) + # + # # restart service + # command = ['/usr/sbin/service', 'opsoro', 'restart'] + # #shell=FALSE for sudo to work. + # subprocess.call(command, shell=False) # ---------------------------------------------------------------------- From 2ef09e45fd8fb2dabf091addbc4451e7b5b11a82 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 13:35:56 +0100 Subject: [PATCH 22/60] Robot sleep/wake behaviour --- src/opsoro/robot.py | 11 ++++++++--- src/opsoro/server/__init__.py | 13 ++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/opsoro/robot.py b/src/opsoro/robot.py index 0a70cfe..453fe3d 100644 --- a/src/opsoro/robot.py +++ b/src/opsoro/robot.py @@ -11,9 +11,6 @@ from opsoro.console_msg import * from opsoro.stoppable_thread import StoppableThread from opsoro.hardware import Hardware -# import opsoro.hardware as hardware -# from opsoro.Hardware.Servo import Hardware - from opsoro.preferences import Preferences from functools import partial @@ -248,5 +245,13 @@ def blink(self, speed): if hasattr(module, 'blink'): module.blink(speed) + def sleep(self): + print_info('Night night... ZZZZzzzz....') + pass + + def wake(self): + print_info('I am awake!') + pass + # Global instance that can be accessed by apps and scripts Robot = _Robot() diff --git a/src/opsoro/server/__init__.py b/src/opsoro/server/__init__.py index 615c4f8..6af159f 100644 --- a/src/opsoro/server/__init__.py +++ b/src/opsoro/server/__init__.py @@ -98,7 +98,7 @@ def __init__(self): self.sockjs_disconnect_cb = {} self.sockjs_message_cb = {} - # if Preferences.check_if_update(): + # if Preferences.is_update_available(): # print_info("Update available") # Preferences.update() @@ -140,6 +140,11 @@ def __init__(self): atexit.register(self.at_exit) def at_exit(self): + print_info('Goodbye!') + + # Sleep robot + Robot.sleep(); + self.stop_current_app() if threading.activeCount() > 0: @@ -284,6 +289,9 @@ def update_users(conn): tornado_app = tornado.web.Application(app_socketrouter.urls + self.user_socketrouter.urls + [(r".*", tornado.web.FallbackHandler, {"fallback": flaskwsgi})]) tornado_app.listen(80) + # Wake up robot + Robot.wake(); + # Start default app startup_app = Preferences.get('general', 'startup_app', None) if startup_app in self.apps: @@ -300,8 +308,7 @@ def update_users(conn): # ioloop.PeriodicCallback(UserSocketConnection.dump_stats, 1000).start() IOLoop.instance().start() except KeyboardInterrupt: - self.stop_current_app() - print "Goodbye!" + print_info('Keyboard interupt') def stop_current_app(self): Robot.stop() From e2ac8a457922f4693d1daf42b6226bdf879edff9 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 14:10:01 +0100 Subject: [PATCH 23/60] Preferences; Update: Add revision number --- src/opsoro/apps/preferences/__init__.py | 1 + src/opsoro/apps/preferences/static/app.js | 2 ++ .../apps/preferences/templates/preferences.html | 8 ++++++++ src/opsoro/updater.py | 16 ++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/src/opsoro/apps/preferences/__init__.py b/src/opsoro/apps/preferences/__init__.py index dd398f0..1c81194 100644 --- a/src/opsoro/apps/preferences/__init__.py +++ b/src/opsoro/apps/preferences/__init__.py @@ -100,6 +100,7 @@ def index(): 'update': { 'available': Updater.is_update_available(), 'branch': Preferences.get('update', 'branch', Updater.get_current_branch()), + 'revision': Preferences.get('update', 'revision', Updater.get_current_revision()), # 'branches': Preferences.get_remote_branches(), 'autoUpdate': Preferences.get('update', 'auto_update', False) }, diff --git a/src/opsoro/apps/preferences/static/app.js b/src/opsoro/apps/preferences/static/app.js index a1292bf..e512ad8 100644 --- a/src/opsoro/apps/preferences/static/app.js +++ b/src/opsoro/apps/preferences/static/app.js @@ -12,6 +12,7 @@ $(document).ready(function () { var self = this; self.available = ko.observable(false); + self.revision = ko.observable(''); self.branch = ko.observable(''); self.branches = ko.observable(); self.autoUpdate = ko.observable(false); @@ -88,6 +89,7 @@ $(document).ready(function () { viewmodel.update().branches(prefsJson.update.branches || undefined); viewmodel.update().autoUpdate(prefsJson.update.autoUpdate || false); viewmodel.update().branch(prefsJson.update.branch || ''); + viewmodel.update().revision(prefsJson.update.revision || ''); viewmodel.behaviour().enabled(prefsJson.behaviour.enabled || false); viewmodel.behaviour().caffeine(prefsJson.behaviour.caffeine || 0); diff --git a/src/opsoro/apps/preferences/templates/preferences.html b/src/opsoro/apps/preferences/templates/preferences.html index 6ebffce..726fbfc 100644 --- a/src/opsoro/apps/preferences/templates/preferences.html +++ b/src/opsoro/apps/preferences/templates/preferences.html @@ -103,6 +103,14 @@
    -->
+
+
+ +
+
+ +
+
Update available! diff --git a/src/opsoro/updater.py b/src/opsoro/updater.py index d3a1f1a..f2ef7c3 100644 --- a/src/opsoro/updater.py +++ b/src/opsoro/updater.py @@ -51,6 +51,22 @@ def get_current_branch(self): print_error("Failed to get current branch, is there a git repo setup?" + str(e)) return "" + def get_current_revision(self): + """ + Retrieves the current git revision of the repository. + + :return: current git revision. + :rtype: string + """ + if self.git is None: + return False + try: + # Request latest commit revision + return str(git.log("--pretty=%h", "-1")) + except Exception as e: + print_error("Failed to get current revision, is there a git repo setup?" + str(e)) + return "" + def get_remote_branches(self): """ Retrieve all git branches of the repository. From 0c62bd9ce61c626a4121880dfb7daddd596dab20 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 14:12:18 +0100 Subject: [PATCH 24/60] Updater bugfix --- src/opsoro/updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opsoro/updater.py b/src/opsoro/updater.py index f2ef7c3..68f1fb2 100644 --- a/src/opsoro/updater.py +++ b/src/opsoro/updater.py @@ -62,7 +62,7 @@ def get_current_revision(self): return False try: # Request latest commit revision - return str(git.log("--pretty=%h", "-1")) + return str(self.git.log("--pretty=%h", "-1")) except Exception as e: print_error("Failed to get current revision, is there a git repo setup?" + str(e)) return "" From d9be8e2947ea00d1405eb055f71b1bcbdb65edc3 Mon Sep 17 00:00:00 2001 From: Stan Date: Thu, 16 Mar 2017 14:14:49 +0100 Subject: [PATCH 25/60] Preferences: Update alignment --- src/opsoro/apps/preferences/templates/preferences.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/opsoro/apps/preferences/templates/preferences.html b/src/opsoro/apps/preferences/templates/preferences.html index 726fbfc..df30594 100644 --- a/src/opsoro/apps/preferences/templates/preferences.html +++ b/src/opsoro/apps/preferences/templates/preferences.html @@ -89,10 +89,10 @@ Update
-
+
-
+
-
+
-
+
From 3b2b2e622fa31bb6e3a6b19f8096cfabf16dc71a Mon Sep 17 00:00:00 2001 From: Stan Date: Fri, 17 Mar 2017 11:11:11 +0100 Subject: [PATCH 26/60] Preferences: layout --- src/opsoro/apps/preferences/templates/preferences.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opsoro/apps/preferences/templates/preferences.html b/src/opsoro/apps/preferences/templates/preferences.html index df30594..b38e109 100644 --- a/src/opsoro/apps/preferences/templates/preferences.html +++ b/src/opsoro/apps/preferences/templates/preferences.html @@ -289,7 +289,7 @@
-
+
From 5a540caf3fc4961bfaa0887917a0ae1fa5f67ddf Mon Sep 17 00:00:00 2001 From: Stan Date: Fri, 31 Mar 2017 16:47:04 +0200 Subject: [PATCH 27/60] Foundation6 update --- src/opsoro/apps/app_template/static/app.js | 4 +- .../app_template/templates/app_template.html | 4 +- src/opsoro/apps/circumplex/static/app.js | 5 - .../templates/lua_scripting.html | 40 +- src/opsoro/apps/preferences/static/app.js | 8 +- .../preferences/templates/preferences.html | 330 +- src/opsoro/apps/sliders/static/app.css | 14 +- .../apps/sliders/templates/sliders.html | 100 +- src/opsoro/apps/social_script/static/app.css | 2 + src/opsoro/apps/social_script/static/app.js | 4 +- .../templates/social_script.html | 33 +- src/opsoro/apps/sounds/templates/sounds.html | 32 - .../touch_graph/templates/touch_graph.html | 99 +- .../apps/visual_programming/static/app.js | 2 +- .../templates/visual_programming.html | 4 +- .../server/static/css/foundation.min.css | 3 +- src/opsoro/server/static/css/opsoro.css | 39 +- src/opsoro/server/static/css/opsoro.min.css | 2 +- src/opsoro/server/static/css/opsoro.scss | 22 +- src/opsoro/server/static/css/opsoro_old.css | 6 +- src/opsoro/server/static/js/foundation.min.js | 5960 --------- .../static/js/foundation/foundation.abide.js | 318 - .../js/foundation/foundation.accordion.js | 67 - .../static/js/foundation/foundation.alert.js | 43 - .../js/foundation/foundation.clearing.js | 558 - .../js/foundation/foundation.dropdown.js | 439 - .../js/foundation/foundation.equalizer.js | 73 - .../js/foundation/foundation.interchange.js | 348 - .../js/foundation/foundation.joyride.js | 924 -- .../server/static/js/foundation/foundation.js | 690 -- .../js/foundation/foundation.magellan.js | 198 - .../js/foundation/foundation.offcanvas.js | 152 - .../static/js/foundation/foundation.orbit.js | 472 - .../static/js/foundation/foundation.reveal.js | 449 - .../static/js/foundation/foundation.slider.js | 267 - .../static/js/foundation/foundation.tab.js | 217 - .../js/foundation/foundation.tooltip.js | 300 - .../static/js/foundation/foundation.topbar.js | 445 - .../static/js/knockout-slider-binding.js | 10 +- src/opsoro/server/static/js/opsoro.js | 58 +- src/opsoro/server/static/js/robot/modules.js | 2 +- src/opsoro/server/static/js/robot/virtual.js | 2 +- .../server/static/js/vendor/foundation.js | 10207 ++++++++++++++++ .../server/static/js/vendor/foundation.min.js | 4 + .../external/jquery/jquery.js | 0 .../images/ui-bg_glass_55_fbf9ee_1x400.png | Bin .../images/ui-bg_glass_65_ffffff_1x400.png | Bin .../images/ui-bg_glass_75_dadada_1x400.png | Bin .../images/ui-bg_glass_75_e6e6e6_1x400.png | Bin .../images/ui-bg_glass_95_fef1ec_1x400.png | Bin .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin .../images/ui-icons_222222_256x240.png | Bin .../images/ui-icons_2e83ff_256x240.png | Bin .../images/ui-icons_454545_256x240.png | Bin .../images/ui-icons_888888_256x240.png | Bin .../images/ui-icons_cd0a0a_256x240.png | Bin .../jquery-ui-sortable/index.html | 0 .../jquery-ui-sortable/jquery-ui.css | 0 .../jquery-ui-sortable/jquery-ui.js | 0 .../jquery-ui-sortable/jquery-ui.min.css | 0 .../jquery-ui-sortable/jquery-ui.min.js | 0 .../jquery-ui.structure.css | 0 .../jquery-ui.structure.min.css | 0 .../jquery-ui-sortable/jquery-ui.theme.css | 0 .../jquery-ui.theme.min.css | 0 .../jquery-ui-touch/jquery-1.7.2.min.js | 0 .../jquery-ui-touch/jquery-ui.min.js | 0 .../jquery.ui.touch-punch.min.js | 0 src/opsoro/server/static/js/vendor/jquery.js | 9808 ++++++++++++++- .../server/static/js/vendor/what-input.js | 335 + src/opsoro/server/templates/_systembar.html | 8 +- src/opsoro/server/templates/apps.html | 8 +- src/opsoro/server/templates/base.html | 1 + .../templates/cockpit/_servo_sliders.html | 22 +- .../server/templates/file_explorer.html | 32 +- src/opsoro/server/templates/login.html | 4 +- src/opsoro/server/templates/page.html | 56 - src/opsoro/server/templates/site_base.html | 14 +- 78 files changed, 20735 insertions(+), 12509 deletions(-) delete mode 100644 src/opsoro/server/static/js/foundation.min.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.abide.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.accordion.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.alert.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.clearing.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.dropdown.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.equalizer.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.interchange.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.joyride.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.magellan.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.offcanvas.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.orbit.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.reveal.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.slider.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.tab.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.tooltip.js delete mode 100644 src/opsoro/server/static/js/foundation/foundation.topbar.js create mode 100644 src/opsoro/server/static/js/vendor/foundation.js create mode 100644 src/opsoro/server/static/js/vendor/foundation.min.js rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/external/jquery/jquery.js (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_glass_55_fbf9ee_1x400.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_glass_65_ffffff_1x400.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_glass_75_dadada_1x400.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_glass_75_e6e6e6_1x400.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_glass_95_fef1ec_1x400.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-bg_highlight-soft_75_cccccc_1x100.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-icons_222222_256x240.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-icons_2e83ff_256x240.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-icons_454545_256x240.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-icons_888888_256x240.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/images/ui-icons_cd0a0a_256x240.png (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/index.html (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.js (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.min.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.min.js (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.structure.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.structure.min.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.theme.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-sortable/jquery-ui.theme.min.css (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-touch/jquery-1.7.2.min.js (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-touch/jquery-ui.min.js (100%) rename src/opsoro/server/static/js/{ => vendor}/jquery-ui-touch/jquery.ui.touch-punch.min.js (100%) create mode 100644 src/opsoro/server/static/js/vendor/what-input.js delete mode 100644 src/opsoro/server/templates/page.html diff --git a/src/opsoro/apps/app_template/static/app.js b/src/opsoro/apps/app_template/static/app.js index 3fb2b19..dc026fa 100644 --- a/src/opsoro/apps/app_template/static/app.js +++ b/src/opsoro/apps/app_template/static/app.js @@ -33,11 +33,11 @@ $(document).ready(function() { // Popup window self.popupTextInput = ko.observable("Hi! This text can be changed. Click on the button to change me!"); self.showPopup = function() { - $("#popup_window").foundation("reveal", "open"); + $("#popup_window").foundation('open'); }; self.closePopup = function() { - $("#popup_window").foundation("reveal", "close"); + $("#popup_window").foundation('close'); }; self.popupButtonHandler = function() { self.closePopup(); diff --git a/src/opsoro/apps/app_template/templates/app_template.html b/src/opsoro/apps/app_template/templates/app_template.html index 55b8bc6..a9e8614 100644 --- a/src/opsoro/apps/app_template/templates/app_template.html +++ b/src/opsoro/apps/app_template/templates/app_template.html @@ -55,9 +55,9 @@ {% endblock %} {% block app_modals %} -