From 12c9474218f835a9443def9b685241db5454ef40 Mon Sep 17 00:00:00 2001
From: neodarz <neodarz@neodarz.net>
Date: Fri, 10 May 2019 22:35:26 +0200
Subject: Remove pyGTK crap

---
 README.md                                |  22 ++-
 parrot_zik/interface/base.py             |  93 ++++-----
 parrot_zik/interface/version2.py         | 317 ++++++++++++-------------------
 parrot_zik/model/version2.py             |  31 +--
 parrot_zik/parrot_zik_tray.py            |  80 --------
 parrot_zik/utils.py                      |  32 ----
 requirements.txt                         |   2 +
 setup.py                                 |  16 +-
 share/icons/zik/Headphone.ico            | Bin 112262 -> 0 bytes
 share/icons/zik/zik-audio-headset.png    | Bin 2885 -> 0 bytes
 share/icons/zik/zik-battery-040.png      | Bin 2424 -> 0 bytes
 share/icons/zik/zik-battery-060.png      | Bin 2537 -> 0 bytes
 share/icons/zik/zik-battery-080.png      | Bin 2617 -> 0 bytes
 share/icons/zik/zik-battery-100.png      | Bin 2603 -> 0 bytes
 share/icons/zik/zik-battery-charging.png | Bin 3602 -> 0 bytes
 share/icons/zik/zik-battery-low.png      | Bin 2334 -> 0 bytes
 win32installer.iss                       |  30 ---
 17 files changed, 192 insertions(+), 431 deletions(-)
 delete mode 100755 parrot_zik/parrot_zik_tray.py
 delete mode 100644 parrot_zik/utils.py
 delete mode 100644 share/icons/zik/Headphone.ico
 delete mode 100644 share/icons/zik/zik-audio-headset.png
 delete mode 100644 share/icons/zik/zik-battery-040.png
 delete mode 100644 share/icons/zik/zik-battery-060.png
 delete mode 100644 share/icons/zik/zik-battery-080.png
 delete mode 100644 share/icons/zik/zik-battery-100.png
 delete mode 100644 share/icons/zik/zik-battery-charging.png
 delete mode 100644 share/icons/zik/zik-battery-low.png
 delete mode 100644 win32installer.iss

diff --git a/README.md b/README.md
index 6f89b58..47b66b1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-Parrot Zik Applet
+Parrot Zik TCP Server
 ========
 
 ## Overview
@@ -9,28 +9,32 @@ https://www.parrot.com/en/audio/parrot-zik-3
 PyParrot Zik is unofficial tool that show Parrot Zik indicator on Windows and Linux.
 Thanks to [@serathius](https://github.com/serathius) for Parrot Zik 2.0 support.
 Thanks to [@moimadmax](https://github.com/moimadmax) for Parrot Zik 3.0 support.
+Thanks to [@m0sia](https://github.com/m0sia/pyParrotZik) for base code and the
+reverse engineering of Parrot Zik communication protocol.
 
-## Windows Usage
+This repo contains some base class without unmaintained pyGTK crap and python3
+compatible code with a simple TCP client/server for use this.
 
-![https://ci.appveyor.com/api/projects/status/7o0v6hy6fqaeulrr?svg=true](https://ci.appveyor.com/api/projects/status/7o0v6hy6fqaeulrr?svg=true)
-Latest build(currently doesn't work):
-https://ci.appveyor.com/project/m0sia/pyParrotZik/build/artifacts
+## Windows Usage
 
-Outdated version that supports only Zik 1.0:
-http://goo.gl/dXij2t  
+Windows support is not tested for the moment. All old code from forked project
+is always here.
 
 ## Linux Usage
 
 1. Connect Parrot Zik with standard bluetooth connection
-2. Install the applet
+2. Install the server
    ```
    python setup install
    ```
-3. Run the applet
+3. Run the server
    ```
    parrot_zik_tray
    ```
 
+Battery status are save all 90 seconds in tmp file. You can use the simple
+client to use the server or build your own TCP client.
+
 ### Linux Requirement
 
 Python-bluez is needed. On ubuntu based distro run
diff --git a/parrot_zik/interface/base.py b/parrot_zik/interface/base.py
index 90caa02..75f368c 100644
--- a/parrot_zik/interface/base.py
+++ b/parrot_zik/interface/base.py
@@ -1,45 +1,21 @@
 from parrot_zik import resource_manager
-from parrot_zik.indicator import Menu
-from parrot_zik.indicator import MenuItem
 from parrot_zik.model.base import BatteryStates
 
-RECONNECT_FREQUENCY = 5000
+RECONNECT_FREQUENCY = 5
 
 
 class ParrotZikBaseInterface(object):
     def __init__(self, indicator):
         self.indicator = indicator
         self.parrot = None
-        self.battery_level = MenuItem("Battery Level:", None, sensitive=False,
-                                      visible=False)
-        self.battery_state = MenuItem("Battery State:", None, sensitive=False,
-                                      visible=False)
-        self.firmware_version = MenuItem("Firmware Version:", None,
-                                         sensitive=False, visible=False)
-        self.settings = MenuItem("Settings", None, visible=False)
-        self.settings_submenu = Menu()
-        self.settings.set_submenu(self.settings_submenu)
-
-        self.auto_connection = MenuItem("Auto Connection", self.toggle_auto_connection,
-                                        checkitem=True)
-        self.settings_submenu.append(self.auto_connection)
-
-        self.indicator.menu.append(self.battery_level)
-        self.indicator.menu.append(self.battery_state)
-        self.indicator.menu.append(self.firmware_version)
-        self.indicator.menu.append(self.settings)
+        self.battery_level = ""
+        self.battery_state = ""
 
     def activate(self, manager):
         self.parrot = self.parrot_class(manager)
-        self.read_battery()
-        self.indicator.info("Connected to: " + self.parrot.friendly_name)
-        self.firmware_version.set_label(
-            "Firmware version: " + self.parrot.version)
-        self.auto_connection.set_active(self.parrot.auto_connect)
-        self.battery_level.show()
-        self.battery_state.show()
-        self.firmware_version.show()
-        self.settings.show()
+        self.indicator.info({"info": "Connected to: " + self.parrot.friendly_name})
+        self.firmware_version = self.parrot.version
+        self.auto_connection = self.parrot.auto_connect
         self.indicator.active_interface = self
 
     @property
@@ -48,48 +24,45 @@ class ParrotZikBaseInterface(object):
 
     def deactivate(self):
         self.parrot = None
-        self.battery_level.hide()
-        self.battery_state.hide()
-        self.firmware_version.hide()
-        self.settings.hide()
-        self.indicator.menu.reposition()
+        self.battery_level = ""
+        self.battery_mode = ""
+        self.firmware_version = ""
         self.indicator.active_interface = None
-        self.indicator.setIcon("zik-audio-headset")
-        self.indicator.info('Lost Connection')
-        self.indicator.reconnect.start(self.indicator, RECONNECT_FREQUENCY)
+        self.indicator.info({"error": "Lost Connection"})
+        self.indicator.reconnect(RECONNECT_FREQUENCY)
 
-    def toggle_auto_connection(self, widget):
+    def read_auto_connection(self):
+        """
+        Return auto connection status.
+        """
         try:
-            self.parrot.auto_connect = self.auto_connection.get_active()
-            self.auto_connection.set_active(self.parrot.auto_connect)
+            data = {"data": {"auto_connection": self.parrot.auto_connect}}
+            self.indicator.info(data)
+            return data
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def refresh(self):
-        self.read_battery()
+    def toggle_auto_connection(self, auto_connection):
+        """
+        Set auto connection mode. Must be 'true' or 'false'.
+        """
+        try:
+            self.parrot.auto_connect = auto_connection
+            return self.read_auto_connection()
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
 
     def read_battery(self):
+        """
+        Return battery level and battery state
+        """
         try:
             self.parrot.refresh_battery()
             battery_level = self.parrot.battery_level
             battery_state = self.parrot.battery_state
+        except AssertionError as e:
+            print(e)
         except resource_manager.DeviceDisconnected:
             self.deactivate()
         else:
-            if battery_state == BatteryStates.CHARGING:
-                self.indicator.setIcon("zik-battery-charging")
-            elif battery_level > 80:
-                self.indicator.setIcon("zik-battery-100")
-            elif battery_level > 60:
-                self.indicator.setIcon("zik-battery-080")
-            elif battery_level > 40:
-                self.indicator.setIcon("zik-battery-060")
-            elif battery_level > 20:
-                self.indicator.setIcon("zik-battery-040")
-            else:
-                self.indicator.setIcon("zik-battery-low")
-
-            self.battery_state.set_label(
-                "State: " + BatteryStates.representation[battery_state])
-            self.battery_level.set_label(
-                "Battery Level: " + str(battery_level))
+            return {"data": {"state": BatteryStates.representation[battery_state], "level": battery_level}}
diff --git a/parrot_zik/interface/version2.py b/parrot_zik/interface/version2.py
index e3ad474..b00eb77 100644
--- a/parrot_zik/interface/version2.py
+++ b/parrot_zik/interface/version2.py
@@ -1,239 +1,170 @@
 import functools
 
 from parrot_zik import resource_manager
-from parrot_zik.indicator import MenuItem, Menu
 from parrot_zik.interface.base import ParrotZikBaseInterface
 from parrot_zik.model.version2 import ParrotZikVersion2
 from parrot_zik.model.version2 import NoiseControlTypes
 from parrot_zik.model.version2 import Rooms
+from parrot_zik.model.version2 import Angles
 
 
 class ParrotZikVersion2Interface(ParrotZikBaseInterface):
     parrot_class = ParrotZikVersion2
 
     def __init__(self, indicator):
-        self.room_dirty = False
-        self.angle_dirty = False
-        self.noise_cancelation_dirty = False
         super(ParrotZikVersion2Interface, self).__init__(indicator)
-        self.noise_cancelation = MenuItem("Noise Control", None, visible=False)
-        self.noise_cancelation_submenu = Menu()
-        self.noise_cancelation.set_submenu(self.noise_cancelation_submenu)
-
-        self.noise_control_cancelation_max = MenuItem(
-            "Max Cancelation", functools.partial(
-                self.toggle_noise_cancelation,
-                NoiseControlTypes.NOISE_CONTROL_MAX), checkitem=True)
-        self.noise_control_cancelation_on = MenuItem(
-            "Normal Cancelation", functools.partial(
-                self.toggle_noise_cancelation,
-                NoiseControlTypes.NOISE_CONTROL_ON), checkitem=True)
-        self.noise_control_off = MenuItem(
-            "Off", functools.partial(
-                self.toggle_noise_cancelation,
-                NoiseControlTypes.NOISE_CONTROL_OFF), checkitem=True)
-        self.noise_control_street_mode = MenuItem(
-            "Street Mode", functools.partial(
-                self.toggle_noise_cancelation,
-                NoiseControlTypes.STREET_MODE), checkitem=True)
-        self.noise_control_street_mode_max = MenuItem(
-            "Street Mode Max", functools.partial(
-                self.toggle_noise_cancelation,
-                NoiseControlTypes.STREET_MODE_MAX), checkitem=True)
-        self.noise_cancelation_submenu.append(self.noise_control_cancelation_max)
-        self.noise_cancelation_submenu.append(self.noise_control_cancelation_on)
-        self.noise_cancelation_submenu.append(self.noise_control_off)
-        self.noise_cancelation_submenu.append(self.noise_control_street_mode)
-        self.noise_cancelation_submenu.append(self.noise_control_street_mode_max)
-
-        self.room_sound_effect = MenuItem(
-            "Room Sound Effect", None, visible=False)
-        self.room_sound_effect_submenu = Menu()
-        self.room_sound_effect.set_submenu(self.room_sound_effect_submenu)
-
-        self.room_sound_effect_enabled = MenuItem(
-            "Enabled", self.toggle_room_sound_effect, checkitem=True)
-        self.rooms = MenuItem("Rooms", None, checkitem=False)
-        self.angle = MenuItem("Angle", None, checkitem=False)
-        self.room_sound_effect_submenu.append(self.room_sound_effect_enabled)
-        self.room_sound_effect_submenu.append(self.rooms)
-        self.room_sound_effect_submenu.append(self.angle)
-
-        self.rooms_submenu = Menu()
-        self.rooms.set_submenu(self.rooms_submenu)
-
-        self.concert_hall_mode = MenuItem(
-            "Concert Hall", functools.partial(self.toggle_room, Rooms.CONCERT_HALL), checkitem=True)
-        self.jazz_mode = MenuItem(
-            "Jazz Club", functools.partial(self.toggle_room, Rooms.JAZZ_CLUB), checkitem=True)
-        self.living_mode = MenuItem(
-            "Living Room", functools.partial(self.toggle_room, Rooms.LIVING_ROOM), checkitem=True)
-        self.silent_mode = MenuItem(
-            "Silent Room", functools.partial(self.toggle_room, Rooms.SILENT_ROOM), checkitem=True)
-        self.rooms_submenu.append(self.concert_hall_mode)
-        self.rooms_submenu.append(self.jazz_mode)
-        self.rooms_submenu.append(self.living_mode)
-        self.rooms_submenu.append(self.silent_mode)
-
-        self.angle_submenu = Menu()
-        self.angle.set_submenu(self.angle_submenu)
-        self.angle_30 = MenuItem(
-            "30", functools.partial(self.toggle_angle, 30), checkitem=True)
-        self.angle_60 = MenuItem(
-            "60", functools.partial(self.toggle_angle, 60), checkitem=True)
-        self.angle_90 = MenuItem(
-            "90", functools.partial(self.toggle_angle, 90), checkitem=True)
-        self.angle_120 = MenuItem(
-            "120", functools.partial(self.toggle_angle, 120), checkitem=True)
-        self.angle_150 = MenuItem(
-            "150", functools.partial(self.toggle_angle, 150), checkitem=True)
-        self.angle_180 = MenuItem(
-            "180", functools.partial(self.toggle_angle, 180), checkitem=True)
-        self.angle_submenu.append(self.angle_30)
-        self.angle_submenu.append(self.angle_60)
-        self.angle_submenu.append(self.angle_90)
-        self.angle_submenu.append(self.angle_120)
-        self.angle_submenu.append(self.angle_150)
-        self.angle_submenu.append(self.angle_180)
-
-        self.flight_mode = MenuItem("Flight Mode", self.toggle_flight_mode,
-                                    checkitem=True, visible=False)
-
-        self.head_detection = MenuItem("Head Detection", self.toggle_head_detection, checkitem=True)
-        self.settings_submenu.append(self.head_detection)
-
-        self.indicator.menu.append(self.room_sound_effect)
-        self.indicator.menu.append(self.noise_cancelation)
-        self.indicator.menu.append(self.flight_mode)
+        self.noise_control_types = NoiseControlTypes.representation
+        self.rooms_types = Rooms.representation
+        self.angles = Angles.representation
 
     def activate(self, manager):
         super(ParrotZikVersion2Interface, self).activate(manager)
-        self._read_noise_cancelation()
-        self.flight_mode.set_active(self.parrot.flight_mode)
-        self._read_sound_effect_room()
-        self._read_sound_effect_angle()
-        self.head_detection.set_active(self.parrot.head_detection)
-
-        sound_effect = self.parrot.sound_effect
-
-        self.room_sound_effect_enabled.set_active(sound_effect)
-        self.concert_hall_mode.set_sensitive(sound_effect)
-        self.jazz_mode.set_sensitive(sound_effect)
-        self.living_mode.set_sensitive(sound_effect)
-        self.silent_mode.set_sensitive(sound_effect)
-
-        self.angle_30.set_sensitive(sound_effect)
-        self.angle_60.set_sensitive(sound_effect)
-        self.angle_90.set_sensitive(sound_effect)
-        self.angle_120.set_sensitive(sound_effect)
-        self.angle_150.set_sensitive(sound_effect)
-        self.angle_180.set_sensitive(sound_effect)
-
-        self.noise_cancelation.show()
-        self.flight_mode.show()
-        self.room_sound_effect.show()
-        self.indicator.menu.reposition()
 
     def deactivate(self):
-        self.noise_cancelation.hide()
-        self.flight_mode.hide()
-        self.room_sound_effect.hide()
         super(ParrotZikVersion2Interface, self).deactivate()
 
-    def toggle_flight_mode(self, widget):
+    def toggle_flight_mode(self, flight_mode):
         try:
-            self.parrot.flight_mode = self.flight_mode.get_active()
-            self.flight_mode.set_active(self.parrot.flight_mode)
+            #self.parrot.flight_mode = flight_mode
+            warning = {'warning': 'Sorry for this moment this function is disable because you need to connect your system on headset with NFC to disable flight mode.'}
+            self.indicator.info(warning)
+            return warning
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def toggle_room(self, room, widget):
+    def read_flight_mode(self):
         try:
-            if not self.room_dirty:
+            data = {'data': {'flight_mode': self.parrot.flight_mode}}
+            self.indicator.info(data)
+            return data
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def toggle_sound_effect_room(self, room):
+        """
+        Define ambiance room. Muse be one of the following room:
+        'concert', 'jazz', 'living', 'silent'.
+        """
+        try:
+            if room in self.rooms_types:
                 self.parrot.room = room
-                self.room_dirty = True
-                self._read_sound_effect_room()
-                self.room_dirty = False
+                data = {'data': {'sound_effect_room': self.parrot.room}}
+                self.indicator.info(data)
+                return data
+            else:
+                data = {'error': "'" + room + "' is not a correct room name"}
+                self.indicator.info(data)
+                return data
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def read_sound_effect_room(self):
+        """
+        Return current ambiance room value.
+        """
+        try:
+            data = {'data': {'sound_effect_type': self.parrot.room}}
+            self.indicator.info(data)
+            return data
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def toggle_sound_effect_room_enabled(self, sound_effect):
+        """
+        Enable or disable the ambiance room. Must be 'true' or 'false'.
+        """
+        try:
+            self.parrot.sound_effect = sound_effect
+            return self.read_sound_effect_room_enabled()
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def _read_sound_effect_room(self):
-        active_room = self.parrot.room
-        room_to_menuitem_map = (
-            (Rooms.CONCERT_HALL, self.concert_hall_mode),
-            (Rooms.JAZZ_CLUB, self.jazz_mode),
-            (Rooms.LIVING_ROOM, self.living_mode),
-            (Rooms.SILENT_ROOM, self.silent_mode),
-        )
-        for room, menu_item in room_to_menuitem_map:
-            menu_item.set_active(room == active_room)
-
-    def toggle_room_sound_effect(self, widget):
+    def read_sound_effect_room_enabled(self):
+        """
+        Return current ambiance room status.
+        """
         try:
-            self.parrot.sound_effect = self.room_sound_effect_enabled.get_active()
-            sound_effect = self.parrot.sound_effect
-            self.room_sound_effect_enabled.set_active(sound_effect)
-            self.concert_hall_mode.set_sensitive(sound_effect)
-            self.jazz_mode.set_sensitive(sound_effect)
-            self.living_mode.set_sensitive(sound_effect)
-            self.silent_mode.set_sensitive(sound_effect)
-            self.angle_30.set_sensitive(sound_effect)
-            self.angle_60.set_sensitive(sound_effect)
-            self.angle_90.set_sensitive(sound_effect)
-            self.angle_120.set_sensitive(sound_effect)
-            self.angle_150.set_sensitive(sound_effect)
-            self.angle_180.set_sensitive(sound_effect)
+            data = {'data': {'sound_effect_state': self.parrot.sound_effect}}
+            self.indicator.info(data)
+            return data
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def toggle_angle(self, angle, widget):
+    def toggle_sound_effect_angle(self, angle):
+        """
+        Define angle, must be one of the following interger:
+        30, 60, 90, 120, 150, 180
+        """
         try:
-            if not self.angle_dirty:
+            if angle in self.angles:
                 self.parrot.angle = angle
-                self.angle_dirty = True
-                self._read_sound_effect_angle()
-                self.angle_dirty = False
+                return self.read_sound_effect_angle()
+            else:
+                data = {'error': "'"+str(angle)+"' is not an accepted angle"}
+                self.indicator.info(data)
+                return data
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def read_sound_effect_angle(self):
+        """
+        Return current sound angle.
+        """
+        try:
+            data = {'data': {'sound_effec_angle': self.parrot.angle}}
+            self.indicator.info(data)
+            return data
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def toggle_noise_control(self, noise_control):
+        """
+        Define noise cancelation mode. Must be one of this value:
+        'NOISE_CONTROL_MAX': Noise reduction maximum
+        'NOISE_CONTROL_ON': Noise reduction enable
+        'NOISE_CONTROL_OFF': Noise reduction disable
+        'STREET_MODE': Street mode
+        'STREET_MODE_MAX': Street mode maximum
+        """
+        try:
+            for noise_control_type, noise_control_value in self.noise_control_types.items():
+                if noise_control == noise_control_type:
+                    self.parrot.noise_control = noise_control_value
+            return self.read_noise_control()
+        except resource_manager.DeviceDisconnected:
+            self.deactivate()
+
+    def read_noise_control(self):
+        """
+        Return current noise cancelation mode.
+        """
+        try:
+            active_noise_control = self.parrot.noise_control
+            for noise_control_type, noise_control in self.noise_control_types.items():
+                if active_noise_control == noise_control:
+                    data = {'data': {'noise_control': noise_control_type}}
+                    self.indicator.info(data)
+                    return data
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def _read_sound_effect_angle(self):
-        active_angle = self.parrot.angle
-        angle_to_menuitem_map = (
-            (30, self.angle_30),
-            (60, self.angle_60),
-            (90, self.angle_90),
-            (120, self.angle_120),
-            (150, self.angle_150),
-            (180, self.angle_180),
-        )
-        for angle, menu_item in angle_to_menuitem_map:
-            menu_item.set_active(angle == active_angle)
-
-    def toggle_noise_cancelation(self, noise_cancelation, widget):
+    def toggle_head_detection(self, head_detection):
+        """
+        Enable or disable head detection. Must be 'true' or 'false'.
+        """
         try:
-            if not self.noise_cancelation_dirty:
-                self.parrot.noise_control = noise_cancelation
-                self.noise_cancelation_dirty = True
-                self._read_noise_cancelation()
-                self.noise_cancelation_dirty = False
+            self.parrot.head_detection = head_detection
+            return self.read_head_detection()
         except resource_manager.DeviceDisconnected:
             self.deactivate()
 
-    def _read_noise_cancelation(self):
-        active_noise_control = self.parrot.noise_control
-        noise_control_to_menuitem_map = (
-            (NoiseControlTypes.NOISE_CONTROL_MAX, self.noise_control_cancelation_max),
-            (NoiseControlTypes.NOISE_CONTROL_ON, self.noise_control_cancelation_on),
-            (NoiseControlTypes.NOISE_CONTROL_OFF, self.noise_control_off),
-            (NoiseControlTypes.STREET_MODE, self.noise_control_street_mode),
-            (NoiseControlTypes.STREET_MODE_MAX, self.noise_control_street_mode_max),
-        )
-        for noise_control, menu_item in noise_control_to_menuitem_map:
-            menu_item.set_active(active_noise_control == noise_control)
-
-    def toggle_head_detection(self, widget):
+    def read_head_detection(self):
+        """
+        Return head detector status.
+        """
         try:
-            self.parrot.head_detection = self.head_detection.get_active()
-            self.head_detection.set_active(self.parrot.head_detection)
+            data = {'data': {'head_detection': self.parrot.head_detection}}
+            self.indicator.info(data)
+            return data
         except resource_manager.DeviceDisconnected:
             self.deactivate()
diff --git a/parrot_zik/model/version2.py b/parrot_zik/model/version2.py
index 0cbdc1a..bbdec6a 100644
--- a/parrot_zik/model/version2.py
+++ b/parrot_zik/model/version2.py
@@ -107,24 +107,25 @@ class NoiseControl(object):
 
 
 class NoiseControlTypes:
-    NOISE_CONTROL_MAX = NoiseControl('anc', 2)
-    NOISE_CONTROL_ON = NoiseControl('anc', 1)
-    NOISE_CONTROL_OFF = NoiseControl('off', 1)
-    STREET_MODE = NoiseControl('aoc', 1)
-    STREET_MODE_MAX = NoiseControl('aoc', 2)
+    representation = {
+        'NOISE_CONTROL_MAX': NoiseControl('anc', 2),
+        'NOISE_CONTROL_ON': NoiseControl('anc', 1),
+        'NOISE_CONTROL_OFF': NoiseControl('off', 1),
+        'STREET_MODE': NoiseControl('aoc', 1),
+        'STREET_MODE_MAX': NoiseControl('aoc', 2),
+    }
 
 
 class Rooms:
-    CONCERT_HALL = 'concert'
-    JAZZ_CLUB = 'jazz'
-    LIVING_ROOM = 'living'
-    SILENT_ROOM = 'silent'
-    representation = {
-        CONCERT_HALL: 'Concert Hall',
-        JAZZ_CLUB: 'Jazz Club',
-        LIVING_ROOM: 'Living Room',
-        SILENT_ROOM: 'Silent Room',
-    }
+    representation = [
+        'concert',
+        'jazz',
+        'living',
+        'silent',
+    ]
+
+class Angles:
+    representation = [30, 60, 90, 120, 150, 180]
 
 class SoundSource:
     LINE_IN = 'line-in'
diff --git a/parrot_zik/parrot_zik_tray.py b/parrot_zik/parrot_zik_tray.py
deleted file mode 100755
index b5fab68..0000000
--- a/parrot_zik/parrot_zik_tray.py
+++ /dev/null
@@ -1,80 +0,0 @@
-from interface.version1 import ParrotZikVersion1Interface
-from interface.version2 import ParrotZikVersion2Interface
-import resource_manager
-import bluetooth_paired_devices
-from indicator import MenuItem
-from indicator import Menu
-from indicator import SysIndicator
-from utils import repeat
-
-REFRESH_FREQUENCY = 30000
-RECONNECT_FREQUENCY = 5000
-
-
-
-class ParrotZikIndicator(SysIndicator):
-    def __init__(self):
- 
-        self.menu = Menu()
-
-        self.info_item = MenuItem("Parrot Zik Not connected",
-                                  None, sensitive=False)
-        self.menu.append(self.info_item)
-
-        self.version_1_interface = ParrotZikVersion1Interface(self)
-        self.version_2_interface = ParrotZikVersion2Interface(self)
-        self.quit_item = MenuItem("Quit", self.quit, checkitem=True)
-        self.menu.append(self.quit_item)
-
-        SysIndicator.__init__(self, icon="zik-audio-headset", menu=self.menu)
-
-        self.active_interface = None
-
-    @repeat
-    def reconnect(self):
-        if self.active_interface:
-            self.reconnect.stop()
-        else:
-            self.info("Trying to connect")
-            try:
-                manager = bluetooth_paired_devices.connect()
-            except bluetooth_paired_devices.BluetoothIsNotOn:
-                self.info("Bluetooth is turned off")
-            except bluetooth_paired_devices.DeviceNotConnected:
-                self.info("Parrot Zik Not connected")
-            except bluetooth_paired_devices.ConnectionFailure:
-                self.info("Failed to connect")
-            else:
-                if manager.api_version.startswith('1'):
-                    interface = self.version_1_interface
-                else:
-                    interface = self.version_2_interface
-                try:
-                    interface.activate(manager)
-                except resource_manager.DeviceDisconnected:
-                    interface.deactivate()
-                else:
-                    self.autorefresh(self)
-                    self.autorefresh.start(self, REFRESH_FREQUENCY)
-                    self.reconnect.stop()
-
-    def info(self, message):
-        self.info_item.set_label(message)
-        print(message)
-
-    @repeat
-    def autorefresh(self):
-        if self.active_interface:
-            self.active_interface.refresh()
-        else:
-            self.reconnect.start(self, RECONNECT_FREQUENCY)
-            self.autorefresh.stop()
-
-    @classmethod
-    def main(cls):
-        try:
-            indicator = cls()
-            cls.reconnect.start(indicator, RECONNECT_FREQUENCY)
-            super(ParrotZikIndicator, cls).main()
-        except KeyboardInterrupt:
-            pass
diff --git a/parrot_zik/utils.py b/parrot_zik/utils.py
deleted file mode 100644
index 86f52cd..0000000
--- a/parrot_zik/utils.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import functools
-from threading import Lock
-
-import gtk
-
-
-class repeat(object):
-    def __init__(self, f):
-        self.f = f
-        self.id = None
-        self.lock = Lock()
-
-    def __call__(self, cls):
-        self.f(cls)
-
-    def start(self, cls, frequency):
-        self.lock.acquire()
-        if not self.id:
-            @functools.wraps(self.f)
-            def run():
-                self.f(cls)
-                return True
-            self.id = gtk.timeout_add(frequency, run)
-        self.lock.release()
-
-    def stop(self):
-        self.lock.acquire()
-        if self.id:
-            gtk.timeout_remove(self.id)
-            self.id = None
-        self.lock.release()
-
diff --git a/requirements.txt b/requirements.txt
index caab114..a2b00e4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,5 @@
 beautifulsoup4 == 4.6.0
 binplist == 0.1.4
 pybluez == 0.22
+dbus-python == 1.2.8
+twisted == 18.9.0
diff --git a/setup.py b/setup.py
index 475b9dc..3e7f723 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@ else:
 
 
 setup(
-    name='parrotziktray',
+    name='parrotzikserver',
     description='Parrot Zik Tray Indicator',
     author="Dmitry Moiseev",
     author_email="m0sia@m0sia.ru",
@@ -20,8 +20,7 @@ setup(
 
     windows=[
         {
-            'script': 'parrot_zik/parrot_zik_tray.py',
-            'icon_resources': [(1, "./share/icons/zik/Headphone.ico")],
+            'script': 'parrot_zik/test_server.py',
         }
     ],
 
@@ -32,22 +31,15 @@ setup(
             'includes': 'cairo, pango, pangocairo, atk, gobject, gio, gtk.keysyms, _winreg',
             'dll_excludes': ['MSVCP90.dll', 'wbtapi.dll', 'irprops.cpl', 'crypt32.dll', 'MSIMG32.DLL', 'NSI.DLL', 'USP10.DLL', 'DNSAPI.DLL']        }
     },
-   
-    data_files=[
-        ("share/icons/zik", glob.glob("share/icons/zik/*.png"))
-            # If using GTK+'s built in SVG support, uncomment these
-            #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'gdk-pixbuf-query-loaders.exe'),
-            #os.path.join(gtk_base_path, '..', 'runtime', 'bin', 'libxml2-2.dll'),
-    ],
 
     install_requires=[
-        'beautifulsoup4', 'pybluez'
+        'beautifulsoup4', 'pybluez', 'dbus-python', 'twisted'
     ],
 
     packages=['parrot_zik', 'parrot_zik.interface', 'parrot_zik.indicator', 'parrot_zik.model'],
     entry_points={
         'console_scripts': [
-            'parrot_zik_tray=parrot_zik.parrot_zik_tray:ParrotZikIndicator.main',
+            'parrot_zik_srv=parrot_zik.test_server:ParrotZik.main',
         ]
     },
     include_package_data=True,
diff --git a/share/icons/zik/Headphone.ico b/share/icons/zik/Headphone.ico
deleted file mode 100644
index 0bddf34..0000000
Binary files a/share/icons/zik/Headphone.ico and /dev/null differ
diff --git a/share/icons/zik/zik-audio-headset.png b/share/icons/zik/zik-audio-headset.png
deleted file mode 100644
index 42164bb..0000000
Binary files a/share/icons/zik/zik-audio-headset.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-040.png b/share/icons/zik/zik-battery-040.png
deleted file mode 100644
index 333e699..0000000
Binary files a/share/icons/zik/zik-battery-040.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-060.png b/share/icons/zik/zik-battery-060.png
deleted file mode 100644
index 5d21461..0000000
Binary files a/share/icons/zik/zik-battery-060.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-080.png b/share/icons/zik/zik-battery-080.png
deleted file mode 100644
index 83fa2fa..0000000
Binary files a/share/icons/zik/zik-battery-080.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-100.png b/share/icons/zik/zik-battery-100.png
deleted file mode 100644
index 0e818c3..0000000
Binary files a/share/icons/zik/zik-battery-100.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-charging.png b/share/icons/zik/zik-battery-charging.png
deleted file mode 100644
index 956e325..0000000
Binary files a/share/icons/zik/zik-battery-charging.png and /dev/null differ
diff --git a/share/icons/zik/zik-battery-low.png b/share/icons/zik/zik-battery-low.png
deleted file mode 100644
index 86546be..0000000
Binary files a/share/icons/zik/zik-battery-low.png and /dev/null differ
diff --git a/win32installer.iss b/win32installer.iss
deleted file mode 100644
index ed30bbc..0000000
--- a/win32installer.iss
+++ /dev/null
@@ -1,30 +0,0 @@
-[Setup]
-AppName=Parrot Zik Tray
-AppVerName=Parrot Zik Tray 0.3
-AppPublisher=m0sia@m0sia.ru
-AppPublisherURL=https://github.com/m0sia/pyParrotZik
-DefaultDirName={pf}\ParrotZikTray
-DefaultGroupName=ParrotZikTray
-DisableProgramGroupPage=true
-OutputBaseFilename=pyParrotZik-win32-installer
-Compression=lzma
-SolidCompression=true
-AllowUNCPath=false
-VersionInfoVersion=0.3
-VersionInfoCompany=m0sia
-VersionInfoDescription=ParrotZikTray
-;PrivilegeRequired=admin
-
-[Dirs]
-Name: {app}; Flags: uninsalwaysuninstall;
-
-[Files]
-Source: dist\*; DestDir: {app}; Flags: ignoreversion recursesubdirs createallsubdirs
-
-[Icons]
-Name: {group}\Parrot Zik Tray; Filename: {app}\ParrotZikTray.exe; WorkingDir: {app}
-
-[Run]
-; If you are using GTK's built-in SVG support, uncomment the following line.
-;Filename: {cmd}; WorkingDir: "{app}"; Parameters: "/C gdk-pixbuf-query-loaders.exe > lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; Description: "GDK Pixbuf Loader Cache Update"; Flags: nowait runhidden
-Filename: {app}\ParrotZikTray.exe; Description: {cm:LaunchProgram,Parrot Zik Tray}; Flags: nowait postinstall skipifsilent
-- 
cgit v1.2.1