Explorar o código

Initial commit

digital %!s(int64=7) %!d(string=hai) anos
achega
45c87034ee
Modificáronse 7 ficheiros con 1170 adicións e 0 borrados
  1. 164 0
      Readme.md
  2. 138 0
      gui.py
  3. 111 0
      lib/beewatch/__init__.py
  4. 268 0
      lib/beewatch/gui/__init__.py
  5. 72 0
      lib/beewatch/pinapi/__init__.py
  6. 152 0
      lib/beewatch/server/__init__.py
  7. 265 0
      server.py

+ 164 - 0
Readme.md

@@ -0,0 +1,164 @@
+# Introduction
+
+## Disclaimer
+
+BeeWatch is still under development and not finised yet. Many of the features mentioned below aren't implemented yet but I'm working on it. If you are exited about a feature or miss one, let me know :)
+
+## The Goal
+
+BeeWatch is designed for beekeepers, no matter if they are hobby and professionals. The project helps you understand your bees and can alert you if they fly away. This works by collecting data about your beehive and analyzing it.
+
+## Raspberry Pi
+
+The Brain of this product is a Raspberry Pi 3, a small computer. It uses various components to collect and analyze data about your bees.
+
+# Features
+
+These are the main features I'm planning to support. Some features can be combined with others.
+
+## Beehouse weighing scale
+
+The weight of your beehouse over time provides a lot of interesting information, for instance
+- honey was produced on a specific day
+- a raw guess of how many bees there are
+- if your bees are moving to a new location
+
+The hardware needed for this:
+ - 5 weighing scales
+ - 5 hx711
+
+## Weather station
+
+The weather conditions are an important factor for the bee's survival and effectiveness.
+- information about temperature, humidity, wind strength, sun radiation
+
+## Solar Panels
+
+Most beehouses aren't placed to a power outlet. Solar panels are an environment friendly way to supply the other parts with electricity.
+
+## Camera
+
+Make pictures or record videos of your beehive. There is also a night-vision camera for the Pi
+
+The hardware required for this (you don't need both cameras):
+- Raspberry Pi camera
+- Raspberry Pi Noir camera
+- Camera extension cord
+
+# What hardware components to buy?
+
+This guide helps you with what comonents you need to buy. The "Basic Setup" and "Other stuff" are the only two essential categories. The "required" row shows if an item is requred for the category, not the whole project.
+
+## Basic Setup
+
+Without an RTC, the raspberry doesn't know what time it is. It can also be synced from the internet, but a RTC is way faster and more dependable. Knowing the time is required for collecting data.
+
+| Name                  | Required  | Amount |
+|:----------------------|:----------|:-------|
+| Raspberry Pi          | essential | 1      |
+| SD card               | essential | 1      |
+| Real time clock (rtc) | advised   | 1      |
+
+## Other stuff needed
+
+This stuff is useful when building things.
+
+| Name                    | Required | Amount |
+|:------------------------|:---------|:-------|
+| mini prototyping board  |          | 2      |
+| small prototyping board |          | 1      |
+| led                     |          | 1      |
+| switch                  |          | 2      |
+
+## Weighing scale
+
+Each load cell needs one HX711. (I'm looking for a way to ditch the HX711 using amplifiers and analog to digital converters). The weighing scale needs 5 load cells but for testing 2 are sufficent.
+
+| Name      | Required  | Amount                 |
+|:----------|:----------|:-----------------------|
+| Load Cell | essential | 5 or 2                 |
+| HX711     | essential | one for each load cell |
+
+## Weather Station
+
+dunno, didn't research this
+
+| Name | Required | Amount |
+|:-----|:---------|:-------|
+|      |          |        |
+
+## Pictures/Videos
+
+There are two camera models for the Raspberry pi, a normal one and a night vision one. The Raspberry has two camera ports, however it is possbile to add more cameras with the help of an extension board
+
+| Name                   | Required                          | Amount          |
+|:-----------------------|:----------------------------------|:----------------|
+| camera                 | you choose                        | you choose      |
+| noir camera            | you choose                        | you choose      |
+| extension cord         | probably                          | depends on how you install the cameras |
+| camera extension board | if you have more than two cameras | depends         |
+
+<!-- ## Dummy
+
+| Name | Required | Amount |
+|:-----|:---------|:-------|
+|      |          |        |
+ -->
+<!--
+
+| Name           | required?            | depends on   | needed for |
+|:---------------|:---------------------|:-------------|:-----------|
+| Raspberry Pi 3 | essential            | sd card, rtc |            |
+| SD card        | essential dependency | --           |            |
+| rtc            | advised dependency   | --           |            |
+| load cells     | optional             | hx711        |            |
+| hx711          | optional dependency  | --           |            |
+| camera         | optional             |              |            |
+| noir camera    |                      |              |            |
+|                |                      |              |            |
+|                |                      |              |            |
+|                |                      |              |            |
+|                |                      |              |            |
+
+ -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<!--  -->

+ 138 - 0
gui.py

@@ -0,0 +1,138 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+#
+## UNITS
+# temperature: Kelvin
+## Imports
+# Python Libraries
+import argparse
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+from gi.repository import Gdk
+import logging
+import random
+import string
+import sys
+import time
+import traceback
+import mylibnetwork
+import yaml
+# My Libraries
+import beewatch
+import beewatch.gui
+import digilib.gui
+import digilib.misc
+
+lgui = logging.getLogger(__name__+".gui")
+
+
+parser = argparse.ArgumentParser(
+    # usage="use this to play",
+    description="BeeWatch Client",
+)
+
+parser.add_argument(
+    "host",
+    type=str,
+    help="hostname/ip address/filename (only if --use-file was specified)"
+)
+parser.add_argument(
+    "port",
+    type=int,
+    default=80540,
+    nargs="?",
+    help="the port on wich the client will connect to. ignored if --use-file \
+        is given"
+)
+parser.add_argument(
+    "-d","--debug",
+    default=False,
+    action="store_true",
+    help="enables logging"
+)
+group_af_family = parser.add_mutually_exclusive_group(required=True)
+group_af_family.add_argument(
+    "-u","--af-unix",
+    dest="af_family",
+    # default=False,
+    action="store_const",
+    const="AF_UNIX",
+    help="""use an AF_UNIX socket (a file). can't be used in combination with
+        --af-inet."""
+    # " will be used \
+    #     instead of an AF_INET socket (hostname/ip address + port)."
+)
+group_af_family.add_argument(
+    "-i","--af_inet",
+    default="AF_INET",
+    dest="af_family",
+    action="store_const",
+    const="AF_INET",
+    help="""use an AF_INET socket (hostname/ip address + port). can't be used
+        with --af-unix"""
+)
+args = parser.parse_args()
+if args.debug:
+    with open("../bee_logging.yaml") as f:
+        data = f.read()
+    config = yaml.safe_load(data)
+    logging.config.dictConfig(config)
+#
+if args.af_family == "AF_INET":
+    port = args.port
+elif args.af_family == "AF_UNIX":
+    port = None
+print(args)
+win = beewatch.gui.BeeWindow(host=args.host,port=port)
+win.start()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#

+ 111 - 0
lib/beewatch/__init__.py

@@ -0,0 +1,111 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+#
+## UNITS
+# speed: meter/second
+# temperature: kelvin
+# rotation: degree/second
+## Imports
+# Python imports
+import logging
+import logging.handlers
+import sys
+import time
+import traceback
+# Third party imports
+import blinker
+import curio
+
+import digilib.network
+# import beewatch.server
+
+log = logging.getLogger(__name__+"")
+log = logging.getLogger(__name__+".psm")
+
+# class PinScriptManager(object):
+#     scripts = []
+#     signals = [
+#     ]
+#     handlers = {
+#     }
+#     def __init__(self):
+#         super(PinScriptManager,self).__init__()
+#     def load_script(self,script):
+#         if script in self.scripts:
+#             lpsm.warn("script '{}' is already loaded!")
+#         self.scripts.add(script)
+#         script.on_load()
+#     # def import_script(self,script)
+#     def unload_script(self,script):
+#         if script in self.scripts:
+#             raise ValueError("script '{}' is not loaded")
+#         script.on_unload()
+#         self.scripts.remove(script)
+
+
+    # def connect(self,signal,func):
+    #     if not signal in self.signals:
+    #         raise ValueError("There is no signal named '{}'".format(signal))
+    #     self.handlers[signal].append(func)
+    # def disconnect(self,signal,func):
+    #     if not signal in self.signals:
+    #         raise NameError("There is no signal named '{}'".format(signal))
+    #     self.handlers[signal].append(func)
+
+
+
+
+# class PinScript(object):
+#     """docstring for Script."""
+#     def __init__(self):
+#         super(PinScript, self).__init__()
+#     def on_load(self):
+#         pass
+#     def on_unload(self):
+#         pass
+
+#
+# class TestPS(PinScript):
+#     def __init__(self):
+
+#
+# if __name__ == "__main__":
+#     psm = PinScriptManager()
+#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#

+ 268 - 0
lib/beewatch/gui/__init__.py

@@ -0,0 +1,268 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+#
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+from gi.repository import Gdk
+import logging
+import logging.config
+import os
+import pprint
+import random
+import string
+import sys
+import time
+import yaml
+# My libraries
+import beewatch
+import beewatch.gui
+import digilib.misc
+import digilib.gui
+import digilib.network
+## Logging
+lgui = logging.getLogger(__name__+".gui")
+
+class ChildConsole(digilib.gui.ChildConsole):
+    def __init__(self,get_client=None):
+        super(ChildConsole,self).__init__(get_client)
+        self.text_buffer_log.set_text("program:HAIIII")
+        self.add_msg(digilib.misc.LOREM_IPSUM,"code")
+        self.add_msg(digilib.misc.LOREM_IPSUM,"code")
+        self.add_msg(digilib.misc.LOREM_IPSUM,"code")
+
+
+class ChildOverview(digilib.gui.ChildOverview):
+    def __init__(self):
+        super(ChildOverview,self).__init__()
+        self.prepare()
+    def prepare(self):
+        self.infobox1 = digilib.gui.InfoFrame()
+        self.infobox2 = digilib.gui.InfoFrame()
+        self.make_infobox_controller()
+        self.make_infobox_weight()
+        self.make_infobox_test(self.infobox1)
+        self.make_infobox_test(self.infobox2)
+        self.layout.attach(self.infobox_controller,0,0,1,1)
+        self.layout.attach(self.infobox_weight,    1,0,1,1)
+        self.layout.attach(self.infobox1,          0,1,1,1)
+        self.layout.attach(self.infobox2,          1,1,1,1)
+    def make_infobox_controller(self):
+        levelbar_cpu = Gtk.LevelBar()
+        levelbar_cpu.set_hexpand(True)
+        levelbar_mem = Gtk.LevelBar()
+        levelbar_mem.set_hexpand(True)
+        self.infobox_controller = digilib.gui.InfoFrame(label="Weight")
+        self.infobox_controller.add_line("uptime","Uptime:","99:59:592017-03-06 12:56")
+        self.infobox_controller.add_line("ip","IP:","30.47.10.O9",None)
+        self.infobox_controller.add_line("cpu","CPU:",30,"%",
+            levelbar_cpu,True)
+        self.infobox_controller.add_line("mem","Memory:",0.40,"%",
+            levelbar_mem,True)
+    def make_infobox_weight(self):
+        self.infobox_weight = digilib.gui.InfoFrame(label="Weight")
+        self.infobox_weight.add_line("total","Total:","50 kg")
+        self.infobox_weight.add_line("bees","Bees:","20 kg")
+        self.infobox_weight.add_line("honey","Honey:","42 kg")
+        self.infobox_weight.add_line("time","Time:","2017-03-06 12:56")
+    def make_infobox_test(self,infobox):
+        infobox.add_line("1","Label:","Value")
+        infobox.add_line("2","Baum:","Haus")
+        infobox.add_line("3","Weight:","40 kg")
+        infobox.add_line("4","Wiff","Woff")
+
+class ChildControl(digilib.gui.ChildControl):
+    def __init__(self):
+        super(ChildControl, self).__init__()
+        self.prepare()
+    def prepare(self):
+        pass
+
+class ChildSettings(digilib.gui.ChildSettings):
+    def __init__(self):
+        super(ChildSettings, self).__init__()
+        self.prepare()
+    def prepare(self):
+        pass
+
+class BeeWindow(digilib.gui.WindowBase):
+    def __init__(self,host,port):
+        super(BeeWindow,self).__init__(title="BeeWatch")
+        self.host = host
+        self.port = port
+        self.client = None
+        self.set_border_width(10)
+        self.tb = digilib.misc.Container()
+        self.prepare()
+        self.add_key_shortcut("Control_L q",self.quit)
+        self.add_key_shortcut("Control_L h e",lgui.info,["hello world"])
+        self.add_key_shortcut("Control_L h i",lgui.info,["hi world"])
+        # self.client = self.make_client()
+    def prepare(self):
+        self.child_console = ChildConsole(self.get_client)
+        self.child_overview = ChildOverview()
+        self.child_control = ChildControl()
+        self.child_settings = ChildSettings()
+        self.child_test = self.make_child_test()
+        self.child_label = self.make_child_label()
+        self.make_toolbar()
+        self.stack = Gtk.Stack()
+        self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
+        self.stack.set_transition_duration(750)
+        self.stack.add_titled(self.child_console, "child_console", "Console")
+        self.stack.add_titled(self.child_overview, "child_overview", "Overview")
+        self.stack.add_titled(self.child_control, "child_control", "Control")
+        self.stack.add_titled(self.child_settings, "child_settings", "Settings")
+        self.stack.add_titled(self.child_test, "check", "Check Button")
+        self.stack.add_titled(self.child_label, "label", "A label")
+        self.stack_switcher = Gtk.StackSwitcher()
+        self.stack_switcher.set_stack(self.stack)
+        self.scrolled_switcher = Gtk.ScrolledWindow()
+        self.scrolled_switcher.add(self.stack_switcher)
+        self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
+        self.vbox.add(self.tb.toolbar)
+        self.vbox.add(self.scrolled_switcher)
+        self.vbox.add(self.stack)
+        self.add(self.vbox)
+        # self.vbox.pack_start(self.stack_switcher, True, True, 0)
+        # self.vbox.pack_start(self.stack, True, True, 0)
+    def make_toolbar(self):
+        self.tb.toolbar = Gtk.Toolbar()
+        self.tb.img_connect = Gtk.Image(stock=Gtk.STOCK_CONNECT)
+        self.tb.img_connect.set_tooltip_text("Connect")
+        self.tb.bconnect = Gtk.ToolButton()
+        self.tb.bconnect.set_icon_widget(self.tb.img_connect)
+        self.tb.bconnect.connect("clicked",self.on_connect_request)
+        self.tb.img_disconnect = Gtk.Image(stock=Gtk.STOCK_DISCONNECT)
+        self.tb.img_disconnect.set_tooltip_text("Disconnect")
+        self.tb.bdisconnect = Gtk.ToolButton()
+        self.tb.bdisconnect.set_icon_widget(self.tb.img_disconnect)
+        self.tb.bdisconnect.connect("clicked",self.on_disconnect_request)
+        self.tb.img_auto_scroll = Gtk.Image(stock=Gtk.STOCK_GOTO_BOTTOM)
+        self.tb.img_auto_scroll.set_tooltip_text("Toggle auto scrolling")
+        self.tb.bauto_scroll = Gtk.ToolButton()
+        self.tb.bauto_scroll.set_icon_widget(self.tb.img_auto_scroll)
+        self.tb.bauto_scroll.connect(
+            "clicked",self.child_console.toggle_scroll)
+        self.tb.img_scroll_down = Gtk.Image(stock=Gtk.STOCK_GO_DOWN)
+        self.tb.img_scroll_down.set_tooltip_text("Toggle auto scrolling")
+        self.tb.bscroll_down = Gtk.ToolButton()
+        self.tb.bscroll_down.set_icon_widget(self.tb.img_scroll_down)
+        self.tb.bscroll_down.connect(
+            "clicked",self.child_console.scroll_down)
+        self.tb.iconnected = Gtk.ToolItem()
+        self.tb.img_connected = Gtk.Image(stock=Gtk.STOCK_YES)
+        self.tb.iconnected.set_visible_horizontal(False)
+        self.tb.iconnected.set_visible_vertical(False)
+        self.tb.img_connected.set_tooltip_text("Connection Status: Connected")
+        self.tb.idisconnected = Gtk.ToolItem()
+        self.tb.img_disconnected = Gtk.Image(stock=Gtk.STOCK_NO)
+        self.tb.img_disconnected.set_tooltip_text(
+            "Connection Status: Disconnected")
+        self.tb.iconnected.add(self.tb.img_connected)
+        self.tb.idisconnected.add(self.tb.img_disconnected)
+        self.tb.toolbar.add(self.tb.iconnected)
+        self.tb.toolbar.add(self.tb.idisconnected)
+        self.tb.toolbar.add(self.tb.bconnect)
+        self.tb.toolbar.add(self.tb.bdisconnect)
+        self.tb.toolbar.add(self.tb.bauto_scroll)
+        self.tb.toolbar.add(self.tb.bscroll_down)
+    def make_child_test(self):
+        box_test = Gtk.FlowBox()
+        for i in range(0,10):
+            checkbutton = Gtk.CheckButton("Click me!")
+            box_test.add(checkbutton)
+        return box_test
+    def make_child_label(self):
+        grid = Gtk.Grid()
+        label = Gtk.Label()
+        label.set_markup("<big>A fancy label</big>")
+        grid.add(label)
+        return grid
+    def make_client(self):
+        client = digilib.network.Client(
+            self.host,
+            self.port,
+            self.child_console.add_msg_threadsafe,
+        )
+        return client
+    def get_client(self):
+        return self.client
+    def quit(self,*args):
+        lgui.debug("quit")
+        if self.client:
+            self.client.stop()
+            # if self.client.is_connected:
+        Gtk.main_quit()
+    def start(self):
+        self.css_provider = Gtk.CssProvider()
+        self.css_provider.load_from_path("config/style.css")
+        screen = Gdk.Screen.get_default()
+        self.style_context = Gtk.StyleContext()
+        self.style_context.add_provider_for_screen(
+            screen,
+            self.css_provider,
+            Gtk.STYLE_PROVIDER_PRIORITY_USER,
+        )
+        self.show_all()
+        self.stack.set_visible_child(self.child_console)
+        Gdk.threads_init()
+        Gtk.main()
+    def on_connect_request(self,widget):
+        try:
+            lgui.debug("connect request")
+            if self.client == None:
+                self.client = self.make_client()
+            if not self.client.is_running():
+                self.client.start()
+            if not self.client.is_connected:
+                if self.client.connect():
+                    self.tb.iconnected.set_visible_horizontal(True)
+                    self.tb.iconnected.set_visible_vertical(True)
+                    self.tb.idisconnected.set_visible_horizontal(False)
+                    self.tb.idisconnected.set_visible_vertical(False)
+                    lgui.debug("client started")
+                else:
+                    lgui.debug(
+                        "client failed to connect, maybe it is connected")
+        except Exception as e:
+            lgui.error("error trying to connect",exc_info=e)
+    def on_disconnect_request(self,widget):
+        try:
+            lgui.debug("disconnect request")
+            if self.client != None:
+                if self.client.is_connected:
+                    self.client.disconnect()
+                    self.tb.iconnected.set_visible_horizontal(False)
+                    self.tb.iconnected.set_visible_vertical(False)
+                    self.tb.idisconnected.set_visible_horizontal(True)
+                    self.tb.idisconnected.set_visible_vertical(True)
+                    lgui.debug("client disconnected")
+                    return
+            lgui.debug(
+                "client failed to disconnect, maybe it wasn't connected")
+        except Exception as e:
+            lgui.error("error trying to disconnect",exc_info=e)
+    def on_scroll_down_request(self,widget):
+        self.child_console.scroll_down()
+    def on_toggle_scroll_request(self,widget):
+        self.child_console.scroll = not self.child_console.scroll
+    def on_exit_button_press(self,*args):
+        self.destroy()
+        Gtk.main_quit()
+        return True

+ 72 - 0
lib/beewatch/pinapi/__init__.py

@@ -0,0 +1,72 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+# Python Libraries
+import logging
+# import time
+import trio
+# My Libraries
+import digilib.pin
+log = logging.getLogger(__name__+"")
+lpin = logging.getLogger(__name__+".pin")
+# log = logging.getLogger(__name__+"")
+
+print("*"*20)
+print("USE TRIO WHEN CODING THE PIN STUFF")
+print("this message is printed by {}".format(__file__))
+print("*"*20)
+
+class LoadCell(digilib.pin.PinControllerBase):
+    """interface for a single load cell"""
+    pass
+
+class BeeWeighingScale(digilib.pin.PinAPIBase):
+    """handles all load cells"""
+    pass
+
+class PinAPIBee(digilib.pin.PinAPIBase):
+    engine_left = None
+    engine_right = None
+    def __init__(self):
+        super(PinAPIBee,self).__init__()
+        self.engine_right = self.make_engine(4,17)
+        self.engine_left = self.make_engine(27,22)
+    def make_engine(self,*args):
+        return digilib.pin.PCEngine(*args)
+    def turn_left(self):
+        right_on = self.engine_right.is_on
+        right_speed = self.engine_right.speed
+        left_on = self.engine_left.is_on
+        left_speed = self.engine_left.speed
+        self.engine_right.turn_on()
+        self.engine_right.set_speed(1)
+        self.engine_left.turn_on()
+        self.engine_left.set_speed(1)
+        trio.sleep(2)
+        if not right_on:
+            self.engine_right.turn_off()
+        self.engine_right.set_speed(right_speed)
+        if not left_on:
+            self.engine_left.turn_off()
+        self.engine_left.set_speed(left_speed)
+        # set engines to previous values
+    def turn_right(self):
+        pass
+        lpin.info("turning right is not implemented")
+        # self.engine_left.stop()
+        # self.engine_right.start()
+        # set engines to previous values

+ 152 - 0
lib/beewatch/server/__init__.py

@@ -0,0 +1,152 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+#
+import logging
+import logging.handlers
+import digilib.network
+import os
+import queue
+import select
+import socket
+import sys
+import threading
+import time
+import traceback
+
+import digilib.pin
+import digilib.network
+import beewatch.pinapi
+
+
+log = logging.getLogger(__name__+"")
+lapi = logging.getLogger(__name__+".api")
+lchat = logging.getLogger(__name__+".chat")
+
+
+
+
+def log_something():
+    lapi.info("logging works")
+
+class BeeWatchServer(digilib.network.Server):
+    """docstring for Server."""
+    def __init__(self,*args,**kwargs):
+        print(kwargs)
+        self.bee_api = beewatch.server.BeeAPI()
+        super(BeeWatchServer, self).__init__(
+            *args,
+            **kwargs,
+            handler=beewatch.server.ConnHandlerBeeWatch,
+            handler_kwargs={"bee_api":self.bee_api}
+        )
+
+class BeeAPI(object):
+    def __init__(self, config_file=None):
+        super(BeeAPI, self).__init__()
+        lapi.info("BeeAPI")
+        self.pin_api = beewatch.pinapi.PinAPIBee()
+    def turn_left(self,respond_method):
+        self.pin_api.turn_left()
+        respond_method("heyooo")
+    def do_something_1(self,*args,respond_method):
+        respond_string ="doing something 1 with '{}'".format("', '".join(args))
+        respond_method(respond_string)
+        lapi.debug(respond_string)
+    def do_something_2(self,*args,respond_method):
+        lapi.debug("doing something 2 with '"+"','".join(args)+"'")
+        respond_method("doing secondary stuff")
+    def do_something_3(self,*args,respond_method):
+        lapi.debug("doing something 3 with '"+"','".join(args)+"'")
+        respond_method("doing three things at once")
+    def log(self,*args):
+        lapi.debug(args)
+    text_to_func = {
+    "turn_left":turn_left,
+    }
+
+class ConnHandlerBeeWatch(digilib.network.ConnHandlerBase):
+    def __init__(self, socket, addr, server, bee_api=None):
+        self.status = "init"
+        self.super_class = super(ConnHandlerBeeWatch, self)
+        self.super_class.__init__(socket, addr, server)
+        lchat.info('hey')
+        self.server = server
+        self.address = addr
+        self.bee_api = bee_api
+        self.command_to_function={
+            "do":self.do,
+            "get_speed":self.speedcheck,
+            "print":self.echo,
+            "None":None,
+        }
+    def welcome_client(self):
+        self.send("this is the server speaking, hello new client!")
+    def handle(self, data_decoded):
+        data_decoded=data_decoded.strip()
+        lchat.info("Client:"+data_decoded)
+        if data_decoded.find(" ") != -1:
+            cmd=data_decoded.split()[0]
+            args=data_decoded.split()[1:]
+        else:
+            cmd=data_decoded
+            args=()
+            kwargs={}
+        # if cmd in self.command_to_function.keys():
+        if cmd in self.bee_api.text_to_func.keys():
+            try:
+                # self.respond(str(args))
+                self.bee_api.text_to_func[cmd](
+                    self.bee_api,
+                    *args,
+                    respond_method=self.respond,
+                    **kwargs,
+                )
+            except:
+                tb = traceback.format_exc()
+                print(tb)
+                self.respond(tb)
+                # for line in tb.split('\n'):
+                #     self.respond(line)
+                #     # print(line)
+                #     # time.sleep(0.001)
+                #     time.sleep(0.1)
+                #     # if line != "\n"
+        else:
+            self.respond("Unknown command")
+        # Notify.Notification.new(
+        #     self.address[0]+" ("+self.server.host+":"+str(self.server.port)+")",
+        #     data_decoded
+        #     ).show()
+    def do(self,func_num,*args,respond_method):
+        arg_to_func = {
+            "1":self.bee_api.do_something_1,
+            "2":self.bee_api.do_something_2,
+            "3":self.bee_api.do_something_3,
+        }
+        arg_to_func[func_num](*args,respond_method=respond_method)
+    def echo(self,*args,**kwargs):
+        lchat.info(str(args))
+        lchat.info(str(kwargs))
+    def speedcheck(self,respond_method):
+        left_speed=str(self.bee_api.c.movement_control.get_speed("left"))
+        right_speed=str(self.bee_api.c.movement_control.get_speed("right"))
+        result = "left: "+left_speed+", right: "+right_speed
+        lchat.info(result)
+        self.respond(result)
+    def respond(self,text,*args):
+        self.send(text)

+ 265 - 0
server.py

@@ -0,0 +1,265 @@
+#! /usr/bin/python3
+#
+## LICENSE
+#    This file is part of BeeWatch.
+#
+#    BeeWatch is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    BeeWatch is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with BeeWatch.  If not, see <http://www.gnu.org/licenses/>.
+#
+## UNITS
+# speed: meter/second
+# temperature: kelvin
+# rotation: degree/second
+
+import argparse
+import gi
+gi.require_version('Notify', '0.7')
+from gi.repository import Notify
+import logging
+import logging.config
+import logging.handlers
+import sys
+import mylibnetwork
+import threading
+import socket
+import traceback
+import time
+import yaml
+
+import beewatch
+# import beewatch.server as beeserver
+import beewatch.server
+
+parser = argparse.ArgumentParser(
+    # usage="use this to play",
+    description="BeeWatch Server",
+)
+
+parser.add_argument(
+    "host",
+    type=str,
+    help="hostname/ip address/filename (only if --use-file was specified)"
+)
+parser.add_argument(
+    "port",
+    type=int,
+    default=80540,
+    nargs="?",
+    help="the port on wich the connection will open up. ignored if --use-file \
+        is given"
+)
+parser.add_argument(
+    "-d","--debug",
+    default=False,
+    action="store_true",
+    help="enables logging"
+)
+group_af_family = parser.add_mutually_exclusive_group()
+group_af_family.add_argument(
+    "-u","--af-unix",
+    dest="af_family",
+    # default=False,
+    action="store_const",
+    const="AF_UNIX",
+    help="""use an AF_UNIX socket (a file). can't be used in combination with
+        --af-inet."""
+    # " will be used \
+    #     instead of an AF_INET socket (hostname/ip address + port)."
+)
+group_af_family.add_argument(
+    "-i","--af_inet",
+    default="AF_INET",
+    dest="af_family",
+    action="store_const",
+    const="AF_INET",
+    help="""use an AF_INET socket (hostname/ip address + port). can't be used
+        with --af-unix"""
+        # (hostname/ip address + port) will be used instead of an AF_INET \
+        # socket (a file)."
+)
+
+args = parser.parse_args()
+print(args)
+if args.debug:
+    with open("../bee_logging.yaml") as f:
+        data = f.read()
+    config = yaml.safe_load(data)
+    logging.config.dictConfig(config)
+
+if args.af_family == "AF_UNIX":
+    port = None
+elif args.af_family == "AF_INET":
+    port = args.port
+
+bee_server = beewatch.server.BeeWatchServer(
+    host=args.host,
+    port=args.port,
+    af_family=args.af_family,
+)
+# bee_api = beeserver.BeeAPI()
+
+# s = mylibnetwork.Server(
+#     host=args.host,
+#     port=port,
+#     handler=beeserver.ConnHandlerBeeWatch,
+#     handler_kwargs={"bee_api":bee_api}
+#     )
+
+bee_server.run()
+try:
+    while True:
+        try:
+            if bee_server.is_alive():
+                bee_server.join(1)
+            else:
+                break
+        except Exception as e:
+            log.warn("an error occured, aborting")
+            log.error(e, exc_info=True)
+            bee_server.stop()
+            break
+except KeyboardInterrupt:
+    print("\r    ", end="\r")
+    logging.warn("keyboardinterrupt! aborting!")
+    bee_server.stop()
+
+
+
+
+sys.exit()
+
+log = logging.getLogger(__name__+".server")
+logc = logging.getLogger(__name__+".chat")
+
+Notify.init("Bee Watch Server")
+#
+# class ConnHandlerBeeWatch(mylibnetwork.ConnHandlerBase):
+#     def __init__(self, socket, addr, server, action=None):
+#         self.status = "init"
+#         self.super_class = super(ConnHandlerBeeWatch, self)
+#         self.super_class.__init__(socket, addr, server)
+#         logc.info('hey')
+#         self.server = server
+#         self.address = addr
+#         self.action=action
+#         self.command_to_function={
+#             "set_speed":self.action.c.movement_control.set_speed,
+#             "mod_speed":self.action.c.movement_control.change_speed,
+#             "get_speed":self.speedcheck,
+#             "print":self.echo,
+#             "None":None,
+#         }
+#     def welcome_client(self):
+#         self.send("this is the server speaking, hello new client!")
+#     def handle(self, data_decoded):
+#         data_decoded=data_decoded.strip()
+#         logc.info("Client:"+data_decoded)
+#         if data_decoded.find(" ") != -1:
+#             cmd=data_decoded.split()[0]
+#             args=data_decoded.split()[1:]
+#         else:
+#             cmd=data_decoded
+#             args=()
+#             kwargs={}
+#         if cmd in self.command_to_function.keys():
+#             try:
+#                 # self.respond(str(args))
+#                 self.command_to_function[cmd](respond_method=self.respond,*args)
+#             except:
+#                 tb = traceback.format_exc()
+#                 print(tb)
+#                 self.respond(tb)
+#                 # for line in tb.split('\n'):
+#                 #     self.respond(line)
+#                 #     # print(line)
+#                 #     # time.sleep(0.001)
+#                 #     time.sleep(0.1)
+#                 #     # if line != "\n"
+#         else:
+#             self.respond("Unknown command")
+#         # Notify.Notification.new(
+#         #     self.address[0]+" ("+self.server.host+":"+str(self.server.port)+")",
+#         #     data_decoded
+#         #     ).show()
+#     def echo(self,*args,**kwargs):
+#         logc.info(str(args))
+#         logc.info(str(kwargs))
+#     def speedcheck(self,respond_method):
+#         left_speed=str(self.action.c.movement_control.get_speed("left"))
+#         right_speed=str(self.action.c.movement_control.get_speed("right"))
+#         result = "left: "+left_speed+", right: "+right_speed
+#         logc.info(result)
+#         self.respond(result)
+#     def respond(self,text,*args):
+#         self.send(text)
+#
+# # logging.basicConfig(
+# #         format = myLogger.fmt + " {process:^^20}",
+# #         datefmt = myLogger.datefmt,
+# #         style = "{",
+# #         level = logging.DEBUG,
+# #         handlers = [
+# #             myLogger.logHandler_console,
+# #         ]
+# #     )
+# # logger_server = logging.getLogger("server")
+# # logger_server.propagate = False
+# # logHandler_server_file = logging.handlers.WatchedFileHandler(filename="logs/server.log")
+# # logHandler_server_file.setFormatter(myLogger.logFormatter)
+# # logHandler_server_file.setLevel(level=logging.DEBUG)
+# # logger_server.addHandler(myLogger.logHandler_console)
+# # logger_server.addHandler(logHandler_server_file)
+# # logger_beewatch = logging.getLogger("BeeWatch")
+# # logger_beewatch.propagate = False
+# # logHandler_beewatch_file = logging.handlers.WatchedFileHandler(filename="logs/beeserver.log")
+# # logHandler_beewatch_file.setFormatter(myLogger.logFormatter)
+# # logHandler_beewatch_file.setLevel(level=logging.DEBUG)
+# # logger_beewatch.addHandler(myLogger.logHandler_console)
+# # logger_beewatch.addHandler(logHandler_beewatch_file)
+#
+#
+# action=beeserver.BoatAction()
+# boat_movement=beeserver.BoatMovement(action.boat_api)
+# action.add_component("movement_control",boat_movement)
+# # engine_left=beeserver.Engine(logger_beewatch,action,{"name":"engine_left"})
+# # engine_right=beeserver.Engine(logger_beewatch,action,{"name":"engine_right"})
+# # action.add_component("engine_left",engine_left)
+# # action.add_component("engine_right",engine_right)
+# argv_dict = dict(zip(range(0,len(sys.argv)),sys.argv))
+# port = argv_dict.get(2,None)
+# if port != None:
+#     port = int(port)
+# s = mylibnetwork.Server(
+#     host=sys.argv[1],
+#     port=port,
+#     handler=ConnHandlerBeeWatch,
+#     handler_kwargs={"action":action}
+#     )
+# bee_server.run()
+# while True:
+#     try:
+#         # print("".join(myLogger.list_stream))
+#         if bee_server.is_alive():
+#             bee_server.join(1)
+#         else:
+#             break
+#     except KeyboardInterrupt:
+#         print("\r    ", end="\r")
+#         logging.warn("keyboardinterrupt! aborting!")
+#         bee_server.stop()
+#         break
+#     except Exception as e:
+#         log.warn("an error occured, aborting")
+#         log.error(e, exc_info=True)
+#         bee_server.stop()
+#         break