コード例 #1
0
ファイル: blockip.py プロジェクト: megan201296/slackbot
import logging
import os
import time
import subprocess

debug = "no" # set to 'yes' to print messages to console

working_dir = "/opt/slackbot/palo-blacklister"

logfile = "%s/blacklist.log" % working_dir
BLfile = "%s/ipv4bl.txt" % working_dir

logging.basicConfig(filename=logfile,format='%(asctime)s %(message)s',level=logging.INFO)
logging.info('Application started. Listening on port: %s',config.listen_port)

app = application = bottle.Bottle()

@app.route('/', method='POST')
def slack_post():
	body = bottle.request.body.read()
	token = bottle.request.forms.get('token')
	team_id = bottle.request.forms.get('team_id')
	team_domain = bottle.request.forms.get('team_domain')
	service_id = bottle.request.forms.get('service_id')
	channel_id = bottle.request.forms.get('channel_id')
	channel_name = bottle.request.forms.get('channel_name')
	timestamp = bottle.request.forms.get('timestamp')
	user_id = bottle.request.forms.get('user_id')
	user_name = bottle.request.forms.get('user_name')
	args = bottle.request.forms.get('text')
	trigger_words = bottle.request.forms.get('trigger_words')
コード例 #2
0
ファイル: server.py プロジェクト: calebwang/fb-graph
import bottle
import urllib
import facebook
import crawl
import os

app_id = '409886029080423'
app_secret = '65045404878c33bac7b538f6f6dbeab9'
tokens = {}

app = bottle.Bottle()
app_access_token = facebook.get_app_access_token(app_id, app_secret)  

@app.route('/')
def home():
    bottle.redirect('/login')

@app.route('/login')
def login():
    args = dict(client_id=app_id, redirect_uri='http://*****:*****@app.route('/callback')
def callback():
    if bottle.request.query.error:
        return '''%s\n<a href="/login">Click here to retry.</a>'''%bottle.request.query.error_description

    args = dict(client_id=app_id, redirect_uri='http://localhost:8080/callback')
    args['client_secret'] = app_secret
コード例 #3
0
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
#
import json
import rest_fruid
import rest_server
import rest_sensors
import rest_bmc
import rest_gpios
import rest_modbus
import rest_slotid
import rest_psu_update
import rest_fcpresent
import bottle

commonApp = bottle.Bottle()


# Handler for root resource endpoint
@commonApp.route('/api')
def rest_api():
    result = {
        "Information": {
            "Description": "Wedge RESTful API Entry",
        },
        "Actions": [],
        "Resources": ["sys"],
    }
    return result

コード例 #4
0
    def __init__(self, robot, host='0.0.0.0', port='6969', quiet=True):
        AbstractServer.__init__(self, robot, host, port)
        self.quiet = quiet
        self.app = bottle.Bottle()
        self.app.install(EnableCors())

        rr = self.restfull_robot

        # Copy Snap files from system directory to user directory. It avoids
        # right issue while PyPot is installed from pip in an admin directory
        snap_system_projects_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'snap_projects')
        xml_files = [os.path.join(snap_system_projects_directory, f)
                     for f in os.listdir(snap_system_projects_directory) if f.endswith('.xml')]
        for xml_file in xml_files:
            dst = os.path.join(get_snap_user_projects_directory(), os.path.basename(xml_file))
            logger.info('Copy snap project from {}, to {}'.format(xml_file, dst))
            shutil.copyfile(xml_file, dst)

        set_snap_server_variables(find_local_ip(), port, path=get_snap_user_projects_directory())
        @self.app.get('/')
        def get_sitemap():
            return '</br>'.join([cgi.escape(r.rule.format()) for r in self.app.routes])

        @self.app.get('/motors/<alias>')
        def get_motors(alias):
            return '/'.join(rr.get_motors_list(alias))

        @self.app.get('/motor/<motor>/get/<register>')
        def get_motor_register(motor, register):
            return str(rr.get_motor_register_value(motor, register))

        @self.app.get('/motors/get/positions')
        def get_motors_positions():
            get_pos = lambda m: rr.get_motor_register_value(
                m, 'present_position')
            msg = '/'.join('{}'.format(get_pos(m))
                           for m in rr.get_motors_list())
            msg = ';'.join('{}'.format(get_pos(m))
                           for m in rr.get_motors_list())
            return msg

        @self.app.get('/motors/alias')
        def get_robot_aliases():
            return '/'.join('{}'.format(alias) for alias in rr.get_motors_alias())

        @self.app.get('/motors/<motors>/get/<register>')
        def get_motors_registers(motors,register):
            """ Allow getting of motors register with a single http request
                Be carefull: with lot of motors, it could overlap the GET max
                    lentgh of your web browser
                """
            motors = motors.split(';')
            return ';'.join(str(rr.get_register_value(m, register)) for m in motors)

        @self.app.get('/motors/set/goto/<motors_position_duration>')
        def set_motors_goto(motors_position_duration):
            """ Allow lot of motors position settings with a single http request
                Be carefull: with lot of motors, it could overlap the GET max
                    lentgh of your web browser
                """
            for m_settings in motors_position_duration.split(';'):
                settings = m_settings.split(':')
                rr.set_goto_position_for_motor(settings[0], float(settings[1]), float(settings[2]))
            return 'Done!'

        @self.app.get('/motors/set/registers/<motors_register_value>')
        def set_motors_registers(motors_register_value):
            """ Allow lot of motors register settings with a single http request
                Be carefull: with lot of motors, it could overlap the GET max
                    lentgh of your web browser
                """
            for m_settings in motors_register_value.split(';'):
                settings = m_settings.split(':')
                rr.set_motor_register_value(settings[0], settings[1], make_tuple(settings[2]))
            return 'Done!'

        # TODO : delete ?
        @self.app.get('/motors/set/positions/<positions>')
        def set_motors_positions(positions):
            positions = map(lambda s: float(s), positions[:-1].split(';'))
            for m, p in zip(rr.get_motors_list(), positions):
                rr.set_motor_register_value(m, 'goal_position', p)
            return 'Done!'

        @self.app.get('/motor/<motor>/set/<register>/<value>')
        def set_reg(motor, register, value):
            rr.set_motor_register_value(motor, register, float(value))
            return 'Done!'

        @self.app.get('/motor/<motor>/goto/<position>/<duration>')
        def set_goto(motor, position, duration):
            rr.set_goto_position_for_motor(
                motor, float(position), float(duration))
            return 'Done!'

        @self.app.get('/snap-blocks.xml')
        def get_pypot_snap_blocks():
            with open(os.path.join(get_snap_user_projects_directory(), 'pypot-snap-blocks.xml')) as f:
                return f.read()

        @self.app.get('/snap/<project>')
        def get_snap_projects(project):
            with open(os.path.join(get_snap_user_projects_directory(),
                                   '{}.xml'.format(project))) as f:
                return f.read()

        @self.app.get('/ip')
        def get_ip():
            return socket.gethostbyname(socket.gethostname())

        @self.app.get('/reset-simulation')
        def reset_simulation():
            if hasattr(robot, 'reset_simulation'):
                robot.reset_simulation()
            return 'Done!'

        @self.app.get('/primitives')
        def get_primitives():
            return '/'.join(rr.get_primitives_list())

        @self.app.get('/primitives/running')
        def get_running_primitives():
            return '/'.join(rr.get_running_primitives_list())

        @self.app.get('/primitive/<primitive>/start')
        def start_primitive(primitive):
            rr.start_primitive(primitive)
            return 'Done!'

        @self.app.get('/primitive/<primitive>/stop')
        def stop_primitive(primitive):
            rr.stop_primitive(primitive)
            return 'Done!'

        @self.app.get('/primitive/<primitive>/pause')
        def pause_primitive(primitive):
            rr.pause_primitive(primitive)
            return 'Done!'

        @self.app.get('/primitive/<primitive>/resume')
        def resume_primitive(primitive):
            rr.resume_primitive(primitive)
            return 'Done!'

        @self.app.get('/primitive/<primitive>/properties')
        def get_primitive_properties_list(primitive):
            return '/'.join(rr.get_primitive_properties_list(primitive))

        @self.app.get('/primitive/<primitive>/get/<property>')
        def get_primitive_property(primitive, property):
            return rr.get_primitive_property(primitive, property)

        @self.app.get('/primitive/<primitive>/set/<property>/<value>')
        def set_primitive_property(primitive, property, value):
            return rr.set_primitive_property(primitive, property, value)

        @self.app.get('/primitive/<primitive>/methodes')
        def get_primitive_methodes_list(primitive):
            return '/'.join(rr.get_primitive_methods_list(primitive))

        @self.app.get('/primitive/<primitive>/call/<method>/<args>')
        def call_primitive_methode(primitive, method, args):
            kwargs = dict(item.split(":") for item in args.split(";"))
            return rr._call_primitive_method(primitive, method, **kwargs)

        # Hacks (no restfull) to record movements
        @self.app.get('/primitive/MoveRecorder/<move_name>/start')
        def start_move_recorder(move_name):
            rr.start_move_recorder(move_name)
            return 'Done!'

        @self.app.get('/primitive/MoveRecorder/<move_name>/stop')
        def stop_move_recorder(move_name):
            rr.stop_move_recorder(move_name)
            return 'Done!'

        @self.app.get('/primitive/MoveRecorder/<move_name>/attach/<motors>')
        def attach_move_recorder(move_name, motors):
            rr.attach_move_recorder(move_name, motors.split(';'))
            return 'Done!'

        @self.app.get('/primitive/MoveRecorder/<move_name>/get_motors')
        def get_move_recorder_motors(move_name):
            motors = rr.get_move_recorder_motors(move_name)
            return '/'.join(motors) if motors is not None else 'None'

        @self.app.get('/primitive/MoveRecorder/<move_name>/start/<motors>')
        def start_move_recorder_with_motors(move_name, motors):
            # raise DeprecationWarning
            rr.start_move_recorder(move_name, motors.split(';'))
            return 'Done!'

        @self.app.get('/primitive/MoveRecorder/<move_name>/remove')
        def remove_move_record(move_name):
            rr.remove_move_record(move_name)
            return 'Done!'

        @self.app.get('/primitive/MoveRecorder')
        def get_available_records():
            return '/'.join(rr.get_available_record_list())

        @self.app.get('/primitive/MovePlayer')
        def get_available_records2():
            return '/'.join(rr.get_available_record_list())

        @self.app.get('/primitive/MovePlayer/<move_name>/start')
        def start_move_player(move_name):
            return str(rr.start_move_player(move_name))

        @self.app.get('/primitive/MovePlayer/<move_name>/start/<move_speed>')
        def start_move_player_with_speed(move_name, move_speed):
            return str(rr.start_move_player(move_name, float(move_speed)))

        @self.app.get('/primitive/MovePlayer/<move_name>/start/<move_speed>/backwards')
        def start_move_player_backwards_with_speed(move_name, move_speed):
            return str(rr.start_move_player(move_name, float(move_speed), backwards=True))

        @self.app.get('/primitive/MovePlayer/<move_name>/stop')
        def stop_move_player(move_name):
            rr.stop_primitive('_{}_player'.format(move_name))
            return 'Done!'

        @self.app.get('/detect/<marker>')
        def detect_marker(marker):
            markers = {
                'tetris': [112259237],
                'caribou': [221052793],
                'lapin': [44616414],
            }
            detected = rr.robot.marker_detector.markers
            return str(any([m.id in markers[marker] for m in detected]))
コード例 #5
0
def main():
    global SESSION_HANDLER
    parser = argparse.ArgumentParser(description="AI for Earth Land Cover")

    parser.add_argument("-v",
                        "--verbose",
                        action="store_true",
                        help="Enable verbose debugging",
                        default=False)
    parser.add_argument("--host",
                        action="store",
                        dest="host",
                        type=str,
                        help="Host to bind to",
                        default="0.0.0.0")
    parser.add_argument("--port",
                        action="store",
                        dest="port",
                        type=int,
                        help="Port to listen on",
                        default=8080)

    parser.add_argument(
        "--disable_checkpoints",
        action="store_true",
        help="Disables the ability to save checkpoints on the server")

    args = parser.parse_args(sys.argv[1:])

    # Create session factory to handle incoming requests
    SESSION_HANDLER = SessionHandler(args)
    SESSION_HANDLER.start_monitor(SESSION_TIMEOUT_SECONDS)

    # Setup logging
    log_path = os.path.join(os.getcwd(), "tmp/logs/")
    setup_logging(log_path, "server")

    # Make sure some directories exist
    os.makedirs("tmp/checkpoints/", exist_ok=True)
    os.makedirs("tmp/downloads/", exist_ok=True)
    os.makedirs("tmp/logs/", exist_ok=True)
    os.makedirs("tmp/output/",
                exist_ok=True)  # TODO: Remove this after we rework
    os.makedirs("tmp/session/", exist_ok=True)

    # Setup the bottle server
    app = bottle.Bottle()

    app.add_hook("after_request", enable_cors)
    app.add_hook(
        "before_request", manage_sessions
    )  # before every request we want to check to make sure there are no session issues

    # API paths
    app.route(
        "/predPatch", method="OPTIONS", callback=do_options
    )  # TODO: all of our web requests from index.html fire an OPTIONS call because of https://stackoverflow.com/questions/1256593/why-am-i-getting-an-options-request-instead-of-a-get-request, we should fix this
    app.route('/predPatch', method="POST", callback=pred_patch)

    app.route("/predTile", method="OPTIONS", callback=do_options)
    app.route('/predTile', method="POST", callback=pred_tile)

    app.route("/downloadAll", method="OPTIONS", callback=do_options)
    app.route('/downloadAll', method="POST", callback=download_all)

    app.route("/getInput", method="OPTIONS", callback=do_options)
    app.route('/getInput', method="POST", callback=get_input)

    app.route("/recordCorrection", method="OPTIONS", callback=do_options)
    app.route('/recordCorrection', method="POST", callback=record_correction)

    app.route("/retrainModel", method="OPTIONS", callback=do_options)
    app.route('/retrainModel', method="POST", callback=retrain_model)

    app.route("/resetModel", method="OPTIONS", callback=do_options)
    app.route('/resetModel', method="POST", callback=reset_model)

    app.route("/doUndo", method="OPTIONS", callback=do_options)
    app.route("/doUndo", method="POST", callback=do_undo)

    app.route("/createSession", method="OPTIONS", callback=do_options)
    app.route("/createSession", method="POST", callback=create_session)

    app.route("/killSession", method="OPTIONS", callback=do_options)
    app.route("/killSession", method="POST", callback=kill_session)

    app.route("/getSessionStatus", method="OPTIONS", callback=do_options)
    app.route("/getSessionStatus", method="POST", callback=get_session_status)

    # Checkpoints
    app.route("/createCheckpoint", method="OPTIONS", callback=do_options)
    app.route("/createCheckpoint",
              method="POST",
              callback=checkpoint_wrapper(args.disable_checkpoints))
    app.route("/getCheckpoints", method="GET", callback=get_checkpoints)

    # Sessions
    app.route("/whoami", method="GET", callback=whoami)

    # Content paths
    app.route("/", method="GET", callback=get_landing_page)
    app.route("/data/basemaps/<filepath:re:.*>",
              method="GET",
              callback=get_basemap_data)
    app.route("/data/zones/<filepath:re:.*>",
              method="GET",
              callback=get_zone_data)
    app.route("/tmp/downloads/<filepath:re:.*>",
              method="GET",
              callback=get_downloads)
    app.route("/favicon.ico", method="GET", callback=get_favicon)
    app.route("/<filepath:re:.*>", method="GET", callback=get_everything_else)

    manage_session_folders()
    session_opts = {
        'session.type': 'file',
        #'session.cookie_expires': 3000, # session cookie
        'session.data_dir': SESSION_FOLDER,
        'session.auto': True
    }
    app = beaker.middleware.SessionMiddleware(app, session_opts)

    server = cheroot.wsgi.Server((args.host, args.port), app)
    server.max_request_header_size = 2**13
    server.max_request_body_size = 2**27

    LOGGER.info("Server initialized")
    try:
        server.start()
    finally:
        server.stop()
コード例 #6
0
 def setUp(self):
     self.engine = create_engine('sqlite:///:memory:')
     self.app = bottle.Bottle(catchall=False)
コード例 #7
0
def start(port=0):
    multiprocessing.set_start_method('spawn')
    bottle.debug(True)
    bottle_app = bottle.Bottle()
    logger = create_logger('geventwebsocket.logging')
    logger.setLevel(logging.DEBUG)
    logger.addHandler(logging.StreamHandler())
    logger.propagate = False
    if app.app_archive:
        zf = ZipFile(app.app_archive, 'r')
        print(zf.namelist())
        print(zf.getinfo('webgui2/dist/index.html'))
        def serve_file(path):
            try:
                print('serving', path, 'from', 'webgui2/dist/' + path)
                info = zf.getinfo('webgui2/dist/' + path)
                if info.is_dir():
                    return bottle.HTTPError(403)
                size = info.file_size
                bottle.response.content_length = size
                bottle.response.content_type = bottle.mimetypes.guess_type(path)[0]
                return zf.open(info, 'r')
            except KeyError:
                return bottle.HTTPError(404)
            except:
                import traceback
                traceback.print_exc()
    else:
        root = Path(__file__).parent.joinpath('dist')
        def serve_file(path):
            return bottle.static_file(path, root)
    httpsock = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_STREAM)
    httpsock.bind(('127.0.0.1', port))
    httpsock.listen()

    token = '1145141919'

    @bottle_app.route("/")
    def serve_root():
        return serve_file("index.html")

    @bottle_app.route('/itemimg/<name>.png')
    def itemimg(name):
        logger.info('serving file %s', name)
        import imgreco.itemdb
        imgreco.itemdb.update_extra_items()
        items = imgreco.itemdb.all_known_items
        itemres = items.get(name, None)
        if itemres:
            bottle.response.content_type = 'image/png'
            return itemres.open()
        else:
            return 404
    
    def readws(ws):
        while True:
            try:
                msg = ws.receive()
            except WebSocketError:
                return None
            if msg is not None:
                if not isinstance(msg, str):
                    continue
                try:
                    obj = json.loads(msg)
                except:
                    logger.error("invalid JSON")
                    continue
                logger.debug("received request %r", obj)
                return obj
            else:
                return None

    @bottle_app.route("/ws")
    def rpc_endpoint():
        wsock : geventwebsocket.websocket.WebSocket = bottle.request.environ.get('wsgi.websocket')
        if not wsock:
            bottle.abort(400, 'Expected WebSocket request.')
        authorized = False
        wsock.send('{"type":"need-authorize"}')
        while True:
            try:
                obj = readws(wsock)
                if obj is None:
                    break
                request_type = obj.get('type', None)
                if request_type == 'web:authorize':
                    client_token = obj.get('token', None)
                    if client_token == token:
                        authorized = True
                        break
            except WebSocketError:
                break
        if authorized:
            logger.info('client authorized')
            from .worker_launcher import worker_process
            inq = multiprocessing.Queue()
            outq = multiprocessing.Queue()
            p = multiprocessing.Process(target=worker_process, args=(inq, outq), daemon=True)
            logger.info('spawning worker process')
            p.start()
            pool : gevent.threadpool.ThreadPool = gevent.get_hub().threadpool
            error = False
            logger.info('starting worker loop')
            outqread = pool.spawn(outq.get)
            wsread = gevent.spawn(readws, wsock)
            while not error:
                for task in gevent.wait((outqread, wsread), count=1):
                    if task is outqread:
                        try:
                            outval = outqread.get()
                        except:
                            logger.error('read worker output failed with exception', exc_info=True)
                            error = True
                            break
                        gevent.spawn(wsock.send, json.dumps(outval))
                        outqread = pool.spawn(outq.get)
                    elif task is wsread:
                        try:
                            obj = wsread.get()
                        except:
                            logger.error('read message from websocket failed with exception', exc_info=True)
                            error = True
                            break
                        if obj is None:
                            error = True
                            break
                        wsread = gevent.spawn(readws, wsock)
                        pool.spawn(inq.put, obj)
            logger.info('worker loop stopped')
            with contextlib.suppress(Exception):
                gevent.kill(wsread)
                wsock.close()
                inq.put_nowait(None)
            p.kill()
    
    @bottle_app.route("/<filepath:path>")
    def serve_static(filepath):
        return serve_file(filepath)

    group = gevent.pool.Pool()
    server = gevent.pywsgi.WSGIServer(httpsock, bottle_app, handler_class=WebSocketHandler, log=logger, spawn=group)
    url = f'http://{server.address[0]}:{server.address[1]}/?token={token}'
    print(url)
    server_task = gevent.spawn(server.serve_forever)
    if port != 0:
        server_task.get()
        return
    from .webhost import get_host
    host = get_host()
    host.start(url, 1080, 820)

    if host.wait_handle:
        # neither gevent nor pywebview like non-main thread
        webview_task = gevent.get_hub().threadpool.spawn(host.wait_handle)
        webview_task.wait()
    else:
        idlechk_interval = getattr(host, 'poll_interval', 60)
        idlecount = 1
        while True:
            gevent.sleep(idlechk_interval)
            if len(group) == 0:
                idlecount += 1
            else:
                idlecount = 0
            if idlecount >= 3:
                print("stopping idle server")
                break
            # gevent.util.print_run_info()
    server.stop()
コード例 #8
0
ファイル: restutils.py プロジェクト: koniolog/dfms
 def __init__(self):
     self._server = None
     self._server_thr = None
     self.app = bottle.Bottle()
コード例 #9
0
ファイル: device_server.py プロジェクト: shaliulab/ethoscope
from zeroconf import ServiceInfo, Zeroconf


from ethoscope.web_utils.control_thread import ControlThread
from ethoscope.web_utils.helpers import *
from ethoscope.web_utils.record import ControlThreadVideoRecording

#from bottle import Bottle, ServerAdapter, request, server_names

try:
    from cheroot.wsgi import Server as WSGIServer
except ImportError:
    from cherrypy.wsgiserver import CherryPyWSGIServer as WSGIServer


api = bottle.Bottle()

tracking_json_data = {}
recording_json_data = {}
update_machine_json_data = {}
ETHOSCOPE_DIR = None

def list_options(category):
    """
    Return a list of str with the names of the classes that can be passed
    for a given category.
    """
    return [cls.__name__ for cls in ControlThread._option_dict[category]['possible_classes']]


class WrongMachineID(Exception):
コード例 #10
0
import urllib.request

import bottle

from bottle import request, response

from . import MANAGEMENT_DAEMON_URL, ROLES
from . import (COLLECTOR_STATE_CONFIGURED, COLLECTOR_STATE_FAILURE,
               COLLECTOR_STATE_NOT_INSTALLED, COLLECTOR_STATE_INSTALLED,
               COLLECTOR_STATE_PARTIAL_FAILURE)
from .config import CONFIG

FILE_UPLOAD_PATH = CONFIG.get('file_upload_path')


APP = bottle.Bottle()
# Default value for "Expires" header (don't allow to cache responses)
EXPIRES_DEFAULT = datetime.datetime(1970, 1, 1)


def abort(code=500, text='Unknown Error.'):
    """Aborts execution and causes a HTTP error."""
    body = json.dumps(dict(message=text))
    raise bottle.HTTPResponse(body, code,
                              headers={'content_type': 'application/json'})


@APP.route('/context.json')
def context():
    """Output context data."""
    # read user information from Apache environment
コード例 #11
0
def start_adminpanel(zigate_instance,
                     host=ADMINPANEL_HOST,
                     port=ADMINPANEL_PORT,
                     mount=None,
                     prefix=None,
                     autostart=True,
                     daemon=True,
                     quiet=True,
                     debug=False):
    '''
    mount: url prefix used to mount bottle application
    prefix: special prefix added when using get_url in template, eg proxy.php
    '''
    app = bottle.Bottle()
    app.install(
        bottle.JSONPlugin(json_dumps=lambda s: dumps(s, cls=DeviceEncoder)))

    def get_url(routename, **kwargs):
        '''
        customized get_url to allow additional prefix args
        '''
        redirect = kwargs.pop('redirect', False)
        scriptname = bottle.request.environ.get('SCRIPT_NAME',
                                                '').strip('/') + '/'
        location = app.router.build(routename, **kwargs).lstrip('/')
        url = bottle.urljoin(bottle.urljoin('/', scriptname), location)
        if prefix and not redirect:
            url = prefix + '?' + bottle.urlencode({'q': url})
        append = '?'
        if '?' in url:
            append = '&'
        url += '{}_={}'.format(append, time.time())
        return url

    def redirect(routename, **kwargs):
        '''
        convenient function to redirect using routename instead of url
        '''
        return bottle.redirect(get_url(routename, redirect=True, **kwargs))

    bottle.BaseTemplate.defaults['get_url'] = get_url
    bottle.BaseTemplate.defaults['zigate'] = zigate_instance
    app.zigate = zigate_instance

    @app.route('/', name='index')
    @bottle.view('index')
    def index():
        connected = zigate_instance.connection and zigate_instance.connection.is_connected(
        )

        grouped_devices = {}
        processed = []

        def add_device_to_group(group, addr, endpoint=''):
            name = 'Missing'
            last_seen = ''
            if addr == zigate_instance.addr:
                name = 'ZiGate'
            zdev = zigate_instance.get_device_from_addr(addr)
            if zdev:
                name = str(zdev)
                last_seen = zdev.info.get('last_seen', '')
            else:
                name = '{} ({})'.format(name, addr)
            group.append({
                'addr': addr,
                'endpoint': endpoint,
                'name': name,
                'last_seen': last_seen
            })

        for group, group_devices in zigate_instance.groups.items():
            grouped_devices[group] = []
            for device in group_devices:
                addr = device[0]
                endpoint = device[1]
                processed.append(addr)
                add_device_to_group(grouped_devices[group], addr, endpoint)

        grouped_devices[''] = []
        for device in zigate_instance.devices:
            if device.addr not in processed:
                add_device_to_group(grouped_devices[''], device.addr)

        port = zigate_instance._port or 'auto'
        if hasattr(zigate_instance, '_host'):
            port = '{}:{}'.format(zigate_instance._host, port)

        return {
            'libversion': zigate_version.__version__,
            'port': port,
            'connected': connected,
            'version': zigate_instance.get_version_text(),
            'model': zigate_instance.model,
            'groups': zigate_instance.groups,
            'grouped_devices': grouped_devices,
        }

    @app.route('/networkmap', name='networkmap')
    @bottle.view('networkmap')
    def networkmap():
        return

    @app.route('/device/<addr>', name='device')
    @bottle.view('device')
    def device(addr):
        device = zigate_instance.get_device_from_addr(addr)
        if not device:
            return redirect('index')
        return {'device': device}

    @app.route('/raw_command', name='raw_command', method=['POST'])
    def raw_command():
        cmd = bottle.request.forms.get('cmd')
        data = bottle.request.forms.get('data')
        cmd = int(cmd, 16)
        zigate_instance.send_data(cmd, data)
        return redirect('index')

    @app.route('/api/permit_join', name='api_permit_join')
    def permit_join():
        zigate_instance.permit_join()
        return redirect('index')

    @app.route('/api/reset', name='api_reset')
    def reset():
        zigate_instance.reset()
        return redirect('index')

    @app.route('/api/led', name='api_led')
    def set_led():
        on = bottle.request.query.get('on', 'true') == 'true'
        zigate_instance.set_led(on)
        return redirect('index')

    @app.route('/api/discover/<addr>', name='api_discover')
    def api_discover(addr):
        zigate_instance.discover_device(addr, True)
        return redirect('device', addr=addr)

    @app.route('/api/refresh/<addr>', name='api_refresh')
    def api_refresh(addr):
        zigate_instance.refresh_device(addr)
        return redirect('device', addr=addr)

    @app.route('/api/remove/<addr>', name='api_remove')
    def api_remove(addr):
        force = bottle.request.query.get('force', 'false') == 'true'
        zigate_instance.remove_device(addr, force)
        return redirect('index')

    @app.route('/device/<addr>/save',
               name='device_save',
               method=['GET', 'POST'])
    def device_save(addr):
        device = zigate_instance.get_device_from_addr(addr)
        if not device:
            return redirect('index')
        device.name = bottle.request.forms.name
        return redirect('device', addr=addr)

    @app.route('/api/devices', name='api_devices')
    def devices():
        devices = [{
            'info': {
                'addr': zigate_instance.addr,
                'ieee': zigate_instance.ieee
            },
            'friendly_name': 'ZiGate'
        }]
        for d in zigate_instance.devices:
            device = d.to_json()
            device['friendly_name'] = str(d)
            devices.append(device)
        return {'devices': devices}

    @app.route('/api/network_table', name='api_network_table')
    def network_table():
        force = bottle.request.query.get('force', 'false') == 'true'
        return {'network_table': zigate_instance.build_neighbours_table(force)}

    kwargs = {'host': host, 'port': port, 'quiet': quiet, 'debug': debug}

    if autostart:
        r_app = app
        if mount:
            root_app = bottle.Bottle()
            root_app.mount(mount, app)
            r_app = root_app
        if daemon:
            t = threading.Thread(target=r_app.run, kwargs=kwargs, daemon=True)
            t.start()
        else:
            r_app.run(**kwargs)
    return app