diff --git a/packages/addons/service/slice/changelog.txt b/packages/addons/service/slice/changelog.txt new file mode 100644 index 0000000000..c88e23ed43 --- /dev/null +++ b/packages/addons/service/slice/changelog.txt @@ -0,0 +1,5 @@ +101 +- Fix sleep.png so all LED's turn off + +100 +- Initial release diff --git a/packages/addons/service/slice/icon/icon.png b/packages/addons/service/slice/icon/icon.png new file mode 100644 index 0000000000..d669c45ed6 Binary files /dev/null and b/packages/addons/service/slice/icon/icon.png differ diff --git a/packages/addons/service/slice/package.mk b/packages/addons/service/slice/package.mk new file mode 100644 index 0000000000..844191aa92 --- /dev/null +++ b/packages/addons/service/slice/package.mk @@ -0,0 +1,47 @@ +################################################################################ +# This file is part of LibreELEC - https://libreelec.tv +# Copyright (C) 2016-present Team LibreELEC +# +# LibreELEC 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 2 of the License, or +# (at your option) any later version. +# +# LibreELEC 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 LibreELEC. If not, see . +################################################################################ + +PKG_NAME="slice" +PKG_VERSION="0" +PKG_REV="101" +PKG_ARCH="any" +PKG_LICENSE="GPL" +PKG_SITE="" +PKG_URL="" +PKG_DEPENDS_TARGET="toolchain" +PKG_SECTION="service" +PKG_SHORTDESC="Controls the LED lights on the Slice box using Kodi actions" +PKG_LONGDESC="Controls the LED lights on the Slice box using Kodi actions" +PKG_AUTORECONF="no" + +PKG_IS_ADDON="yes" +PKG_ADDON_NAME="Slice" +PKG_ADDON_PROJECTS="Slice Slice3" +PKG_ADDON_TYPE="xbmc.service" + +make_target() { + : +} + +makeinstall_target() { + : +} + +addon() { + : +} diff --git a/packages/addons/service/slice/source/default.py b/packages/addons/service/slice/source/default.py new file mode 100644 index 0000000000..214b03a18a --- /dev/null +++ b/packages/addons/service/slice/source/default.py @@ -0,0 +1,237 @@ +################################################################################ +# This file is part of LibreELEC - https://libreelec.tv +# Copyright (C) 2016-present Team LibreELEC +# +# LibreELEC 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 2 of the License, or +# (at your option) any later version. +# +# LibreELEC 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 LibreELEC. If not, see . +################################################################################ + +from PIL import Image + +import os +import threading +import time +import Queue +import xbmc +import xbmcaddon + +''' +ffwd.png +pause.png +play.png +quit.png +rew.png +shutdown.png +skipf.png +skipr.png +sleep.png +startup.png +stop.png +wake.png +''' + +__addon__ = xbmcaddon.Addon() +__path__ = __addon__.getAddonInfo('path') + +class PNGPatternPlayer(threading.Thread): + + def __init__(self): + threading.Thread.__init__(self) + self.path = __path__ + "/resources/media/ledpatterns" + self.patterns = Queue.Queue() + self.responses = Queue.Queue() + self.stopped = False + self.memo = {} + self.start() + + def setPath(self, path): + if self.path != path: + self.path = path + self.memo = {} + + def clearPattern(self): + with open('/dev/ws2812', 'wb') as f: + f.write(bytearray(25)) + + def playPattern(self, file, delay): + xbmc.log('playing pattern: %s' % file, xbmc.LOGNOTICE) + + 'get pixel data from a cache if available, otherwise load and calculate' + if file not in self.memo: + image = Image.open(file) + pixels = image.load() + width, height = image.size + data = [] + + for y in range(height): + x_pixels = [] + for x in range(width): + pixel = [] + r, g, b, a = pixels[x, y] + pixel.append(hex(r)[2:].zfill(2)) + pixel.append(hex(g)[2:].zfill(2)) + pixel.append(hex(b)[2:].zfill(2)) + pixel.append(hex(a)[2:].zfill(2)) + x_pixels.append(''.join(str(e) for e in pixel)) + data.append(' '.join(str(e) for e in x_pixels)) + + self.memo[file] = data + + for hexline in self.memo[file]: + if not self.stopped: + with open('/dev/ws2812', 'wb') as f: + f.write(bytearray.fromhex(hexline)) + time.sleep(delay) + else: + break + + def play(self, file, repeat=False, delay=0.030, wait=None): + self.stopped = True + + if wait is not None: + # wait up to specified time if this pattern is to be processed synchronously + self.patterns.put((file, repeat, delay, True)) + try: + result = self.responses.get(block=True, timeout=wait) + except Queue.Empty: + pass + else: + self.patterns.put((file, repeat, delay, False)) + + def stop(wait=None): + self.play(None, wait=wait) + + def run(self): + repeat = False + + while True: + try: + (file, repeat, delay, wait) = self.patterns.get(block=True, timeout=0 if repeat and not self.stopped else None) + + self.stopped = False + + if file is not None: + self.playPattern("%s/%s.png" % (self.path, file), delay) + else: + self.clearPattern() + + if wait: + self.responses.put(True) + + # Queue will be empty if we're repeating the last pattern and there is no new work + except Queue.Empty: + self.playPattern("%s/%s.png" % (self.path, file), delay) + +class SlicePlayer(xbmc.Player): + + def __init__(self, *args, **kwargs): + xbmc.Player.__init__(self) + + 'maps kodi player speed to delay in seconds' + self.speed_map = { 1: 0.060, + 2: 0.040, + 4: 0.035, + 8: 0.030, + 16: 0.025, + 32: 0.015, + } + + self.speed = 1 + patterns.play('startup', False, 0.02) + + def onPlayBackEnded(self): + 'Will be called when Kodi stops playing a file' + + patterns.play('stop') + + def onPlayBackPaused(self): + 'Will be called when user pauses a playing file' + + patterns.play('pause') + + def onPlayBackResumed(self): + 'Will be called when user resumes a paused file' + + patterns.play('play') + + def onPlayBackSeek(self, iTime, seekOffset): + 'Will be called when user seeks to a time' + + # todo: not working + + xbmc.log('time offset: %d' % iTime, xbmc.LOGNOTICE) + xbmc.log('seek offset: %d' % seekOffset, xbmc.LOGNOTICE) + + if seekOffset > 0: + patterns.play('skipf') + else: + patterns.play('skipr') + + def onPlayBackSeekChapter(self, chapter): + 'Will be called when user performs a chapter seek' + pass + + def onPlayBackSpeedChanged(self, speed): + 'Will be called when players speed changes. (eg. user FF/RW)' + + xbmc.log('seek speed: %d' % speed, xbmc.LOGNOTICE) + + self.speed = speed + + if self.speed != 1: + patterns.play('ffwd' if self.speed > 0 else 'rew', True, self.speed_map[self.speed]) + else: + patterns.stop() + #OR: patterns.play('play') ??? + + def onPlayBackStarted(self): + 'Will be called when Kodi starts playing a file' + + patterns.play('play') + + def onPlayBackStopped(self): + 'Will be called when user stops Kodi playing a file' + + patterns.play('stop') + +class SliceMonitor(xbmc.Monitor): + + def __init__(self, *args, **kwargs): + xbmc.Monitor.__init__(self) + + def onScreensaverActivated(self): + 'Will be called when screensaver kicks in' + + patterns.play('sleep') + + def onScreensaverDeactivated(self): + 'Will be called when screensaver goes off' + + patterns.play('wake') + + def onSettingsChanged(self): + 'Will be called when addon settings are changed' + + # meh + +if (__name__ == "__main__"): + patterns = PNGPatternPlayer() + player = SlicePlayer() + monitor = SliceMonitor() + + monitor.waitForAbort() + patterns.play('shutdown', wait=5.0) + + del SliceMonitor + del SlicePlayer + del PNGPatternPlayer \ No newline at end of file diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/ffwd.png b/packages/addons/service/slice/source/resources/media/ledpatterns/ffwd.png new file mode 100644 index 0000000000..5bee66fb5c Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/ffwd.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/pause.png b/packages/addons/service/slice/source/resources/media/ledpatterns/pause.png new file mode 100644 index 0000000000..60a480f104 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/pause.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/play.png b/packages/addons/service/slice/source/resources/media/ledpatterns/play.png new file mode 100644 index 0000000000..ae89019328 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/play.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/quit.png b/packages/addons/service/slice/source/resources/media/ledpatterns/quit.png new file mode 100644 index 0000000000..667ada77e6 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/quit.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/rew.png b/packages/addons/service/slice/source/resources/media/ledpatterns/rew.png new file mode 100644 index 0000000000..0420bee290 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/rew.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/shutdown.png b/packages/addons/service/slice/source/resources/media/ledpatterns/shutdown.png new file mode 100644 index 0000000000..d4fde7ee7b Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/shutdown.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/skipf.png b/packages/addons/service/slice/source/resources/media/ledpatterns/skipf.png new file mode 100644 index 0000000000..2018e325eb Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/skipf.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/skipr.png b/packages/addons/service/slice/source/resources/media/ledpatterns/skipr.png new file mode 100644 index 0000000000..9292082b82 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/skipr.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/sleep.png b/packages/addons/service/slice/source/resources/media/ledpatterns/sleep.png new file mode 100644 index 0000000000..d4a6af639d Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/sleep.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/startup.png b/packages/addons/service/slice/source/resources/media/ledpatterns/startup.png new file mode 100644 index 0000000000..282954b4a8 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/startup.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/stop.png b/packages/addons/service/slice/source/resources/media/ledpatterns/stop.png new file mode 100644 index 0000000000..e02589b813 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/stop.png differ diff --git a/packages/addons/service/slice/source/resources/media/ledpatterns/wake.png b/packages/addons/service/slice/source/resources/media/ledpatterns/wake.png new file mode 100644 index 0000000000..31944073b0 Binary files /dev/null and b/packages/addons/service/slice/source/resources/media/ledpatterns/wake.png differ