Code Monkey home page Code Monkey logo

tc420's Introduction

TC420 LED Controller Python Library and Command Line Interface

TC420 is a LED dimmer/controller mainly used for aquarium lightning. There is an attached software, PLED, you can use for programming it, but it is not very well written, and not good for automation tasks. Also it is Windows only. You can found more information on its fun (not official) site: https://www.tc420.net/.

I reverse engineered the USB protocol the device uses and wrote this library and CLI tool for making endless possibilities from this device. I successfully implemented all the functions PLED.exe have.

The library is cross platform, works everywhere where libusb works. But because it is a HID device, and MacOS does not allow to detach kernel drivers of HID devices, on MacOS it is extremely hard to make it work in current form. But I tested on Windows and Linux, and works fine there. It works on (all kinds of) Raspberry Pi. (Actually there is a python library for HID devices, so theoretically it is possible to rewrite the lib using hidapi, and then it could work on MacOS as well, pull requests are welcome...)

It has a full featured CLI, which can act as a reference for the libray. Also you can use it for automation, or just for fun.

Possibilities / ideas

  • You can program your device in shell scripts / batch files, or with Python programs
  • You can run immediate scenes, e.g. a sunset or sunrise by a click to attract your guests
  • It is possible to access the device remotely by e.g. a Raspberry Pi Zero W
  • A web / mobile application can be written to start scenes, or modify program of device (not yet written by myself)
  • Different color themes on sunny/rainy/cloudy days, by using online weather sources
  • Real sunset and sunrise program every day by using sunset/sunrise database.
  • ...

Install

Linux

  • Install the library:
pip3 install tc420
  • Install libusb if not installed. On Raspberry pi it is installed by default.
  • Create a plugdev group if not exists, it exists by default in all Debian based distros.
  • Enable the access of the device by users in plugdev group with an udev rule found here: 99-tc420.rules. Put that (by root user) in /etc/udev/rules.d/, then replug your device.
  • Put yourself into the plugdev group then relogin:
sudo adduser your_user_name plugdev

Windows

pip install tc420

From source

This description works without modification on Linux, on Windows, you may need to use pip instead of pip3 and python instead of python3. And the activate.bat is in the Scripts folder inside venv.

  • Clone package from GitHub:
git clone https://github.com/wallneradam/tc420.git
  • Install virtualenv (globally) if not yet installed:
sudo -H pip3 install virtualenv
  • Create a VirtualEnv inside the cloned directory:
virtualenv -p python3 venv
  • Activate it:
./venv/bin/activate
  • Install package with requirements:
pip install -e .

Now you have tc420 command in your virtual environment.

Usage

Both the library and the CLI tool is documented and the source code is commented, so you can find all information inside them.

CLI

You can have the help of tc420 command by running:

tc420 --help

This will only give you brief information about all commands. You can have full description of every commands by running: tc420 [command] --help e.g.:

tc420 mode --help

Getting started

For checking if everything is working you can sync the clock:

tc420 time-sync

Or you can run the demo which randomly fades in-out all channels:

tc420 demo

If something is not working, you probably not installed libusb well, or you need to check if you have permissions to access the device.

tc420's People

Contributors

crmtechsol avatar wallneradam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

tc420's Issues

Group' object has no attribute 'resultcallback'

Got a "AttributeError: 'Group' object has no attribute 'resultcallback'. Did you mean: 'result_callback'?" on a Python 3.11.2 (Raspian Bookworm).
Changing line 304 as suggested fixed this.

Partial success

Hi,

I've installed according to the instructions, from source. I'm using Mint 20.2 (the Ubuntu based one), and setting the clock works fine. However, playing the example doesn't. Not uite sure where to look. On the same machine, using vbox/win10 and Pled, everything is fine.

lsusb says
Bus 001 Device 013: ID 0888:4000 MindMotion SOC Solutions MM32 Custom HID

This is the output:

/linux.sh 
/home/chris/Public/tc420/tc420/__main__.py:286: DeprecationWarning: 'resultcallback' has been renamed to 'result_callback'. The old name will be removed in Click 8.1.
  @cmd_group.resultcallback()
Syncing time... OK.
Initialize playing 'Play'... Traceback (most recent call last):
  File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/home/chris/Public/tc420/tc420/__main__.py", line 304, in <module>
    main()
  File "/home/chris/Public/tc420/tc420/__main__.py", line 300, in main
    cmd_group()
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/core.py", line 1137, in __call__
    return self.main(*args, **kwargs)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/core.py", line 1062, in main
    rv = self.invoke(ctx)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/core.py", line 1699, in invoke
    rv.append(sub_ctx.command.invoke(sub_ctx))
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/chris/Public/tc420/tc420/__main__.py", line 205, in play
    ctx.obj.dev.play(name=name, adapter=adapter, onchange_callback=onchange_callback)
  File "/home/chris/Public/tc420/tc420/tc420.py", line 413, in play
    res = self.send(PlayInitPacket(name))
  File "/home/chris/Public/tc420/tc420/tc420.py", line 322, in send
    res_pkt = TC420Packet(payload=self.in_ep.read(64, timeout=self.timeout))
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/usb/core.py", line 423, in read
    return self.device.read(self, size_or_buffer, timeout)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/usb/core.py", line 1029, in read
    ret = fn(
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/usb/backend/libusb1.py", line 864, in intr_read
    return self.__read(self.lib.libusb_interrupt_transfer,
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/usb/backend/libusb1.py", line 954, in __read
    _check(retval)
  File "/home/chris/Public/tc420/venv/lib/python3.8/site-packages/usb/backend/libusb1.py", line 602, in _check
    raise USBTimeoutError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBTimeoutError: [Errno 110] Operation timed out

Jump flag ignored or wrong?

Hi,

I want to add a solenoid to the tc420 controller and this supports only 0 or 100% (12v)

I used this command (in a script below) with negative value on channel 5
(first 4 are for rgbw leds)

But the controller is fading vs jump (tested between 09:29 and 09:30) and the solenoid is buzzing like hell for a minute
If I measure the voltage I can see it is fading in that minute

with debug I see that the jump_flag is int 16, but I do not have windows and the tc420 soft to compare
do I use it wrong? or is this an issue

python3 -m tc420 \
    mode \
        -n "main" \
        -b 0 \
        -s  09:00 0 0 0 0 -0 \
        -s  09:29 0 5 0 2 -0 \
        -s  09:30 0 5 0 2 -100 \
        -s  10:00 10 15 10 10 -100 \
        -s  13:00 30 30 20 10 -100 \
        -s  16:30 30 20 30 10 -100 \
        -s  17:00 30 20 30 10 -0 \
        -s  17:30 10 0 2 5 -0 \
        -s  18:00 0 0 5 2 -0 \
        -s  19:00 0 0 0 0 -0

Connect multiple TC420

Currently the CLI and the underlying class TC420 only support a single light controller.

An extension is currently in the works in schwabix-1311/TC420 for use in schwabix-1311/aquaPI (with the German discussion in this repo's discussion area).

Not working on Fedora 38

Not working on Fedora 38, when executing tc420 --help I get this error:

Traceback (most recent call last):
  File "/home/miguelangel/.local/bin/tc420", line 5, in <module>
    from tc420.__main__ import main
  File "/home/miguelangel/.local/lib/python3.12/site-packages/tc420/__main__.py", line 286, in <module>
    @cmd_group.resultcallback()
     ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Group' object has no attribute 'resultcallback'. Did you mean: 'result_callback'?

I created plugdev group, added my user, re-logged in but did not work.

udev rules for Debian Bookworm incomplete

On Debian, you need to set permissions for the HID device, too:

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0888", ATTRS{idProduct}=="4000", MODE="0664", GROUP="plugdev"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0888", ATTRS{idProduct}=="4000", GROUP="plugdev", MODE="0664"

Then you need to trigger (i think) the systemd-udevd.service:

systemctl daemon-reload
udevadm control --reload-rules
udevadm trigger

not working in Win10 + python 3.9.5 + libusb 1.0.24b1

Hi!
I just tried to run this on Win10 after following the install instructions and I get the following error:

(base) C:\>tc420 time-sync
Traceback (most recent call last):
  File "c:\miniconda3\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\miniconda3\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Miniconda3\Scripts\tc420.exe\__main__.py", line 7, in <module>
  File "c:\miniconda3\lib\site-packages\tc420\__main__.py", line 300, in main
    cmd_group()
  File "c:\miniconda3\lib\site-packages\click\core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "c:\miniconda3\lib\site-packages\click\core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "c:\miniconda3\lib\site-packages\click\core.py", line 1668, in invoke
    super().invoke(ctx)
  File "c:\miniconda3\lib\site-packages\click\core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "c:\miniconda3\lib\site-packages\click\core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "c:\miniconda3\lib\site-packages\click\decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "c:\miniconda3\lib\site-packages\tc420\__main__.py", line 79, in cmd_group
    ctx.obj.dev = TC420()
  File "c:\miniconda3\lib\site-packages\tc420\tc420.py", line 301, in __init__
    if self.dev.is_kernel_driver_active(0):
  File "c:\miniconda3\lib\site-packages\usb\core.py", line 1108, in is_kernel_driver_active
    return self._ctx.backend.is_kernel_driver_active(
  File "c:\miniconda3\lib\site-packages\usb\backend\libusb1.py", line 915, in is_kernel_driver_active
    return bool(_check(self.lib.libusb_kernel_driver_active(dev_handle.handle,
  File "c:\miniconda3\lib\site-packages\usb\backend\libusb1.py", line 600, in _check
    raise NotImplementedError(_strerror(ret))
NotImplementedError: Operation not supported or unimplemented on this platform

libusb version is 1.0.24 (https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-1.0.24/libusb-1.0.24.7z/download)
I copied:
libusb-1.0.24\MinGW64\dll\libusb-1.0.dll -> Windows\System32
libusb-1.0.24\MinGW32\dll\libusb-1.0.dll -> Windows\SysWOW64

libusb-1.0.24\MinGW64\dll\libusb-1.0.lib -> Miniconda3\libs
libusb-1.0.24\MinGW64\dll\libusb-1.0.lib -> Miniconda3\Library\lib

python is 3.9.5 with the following packages:

Package                Version
---------------------- -------------------
brotlipy               0.7.0
certifi                2021.5.30
cffi                   1.14.6
chardet                4.0.0
click                  8.0.3
colorama               0.4.4
conda                  4.10.3
conda-package-handling 1.7.3
cryptography           3.4.7
idna                   2.10
importlib-metadata     4.9.0
importlib-resources    5.4.0
libusb                 1.0.24b1
menuinst               1.4.16
packaging              21.3
pip                    21.1.3
pkg-about              1.0.3
pycosat                0.6.3
pycparser              2.20
pyOpenSSL              20.0.1
pyparsing              3.0.6
PySocks                1.7.1
pyusb                  1.2.1
pywin32                228
requests               2.25.1
ruamel-yaml-conda      0.15.100
setuptools             52.0.0.post20210125
six                    1.16.0
tc420                  0.2.1
tqdm                   4.61.2
urllib3                1.26.6
wheel                  0.36.2
win-inet-pton          1.1.0
wincertstore           0.2
zipp                   3.6.0

Can you help me understand what to do to make this work?

Thank you!

error using tc420 demo on raspi4 4GB with fresh bullseye installation

Hi and thanks for great work.
The installation worked without errors and I can synchronise the time with tc420-cli time-sync.
But when I run tc420-cli demo -c 1 0 0 0 0 or just tc420-cli demo I get an error message.
I am using a RaspberryPi 4 with Bullseye operating system and Python 3.9.
thanks for help
Oliver

root@aquarium2:/opt# tc420 demo -c 1 0 0 0 0
Initialize playing 'Demo'... Traceback (most recent call last):
  File "/usr/local/bin/tc420", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/dist-packages/tc420/__main__.py", line 300, in main
    cmd_group()
  File "/usr/lib/python3/dist-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1289, in invoke
    rv.append(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/decorators.py", line 21, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.9/dist-packages/tc420/__main__.py", line 279, in demo
    ctx.obj.dev.play(name="Demo", adapter=adapter, onchange_callback=onchange)
  File "/usr/local/lib/python3.9/dist-packages/tc420/tc420.py", line 410, in play
    res = self.send(PlayInitPacket(name))
  File "/usr/local/lib/python3.9/dist-packages/tc420/tc420.py", line 319, in send
    res_pkt = TC420Packet(payload=self.in_ep.read(64, timeout=self.timeout))
  File "/usr/local/lib/python3.9/dist-packages/usb/core.py", line 423, in read
    return self.device.read(self, size_or_buffer, timeout)
  File "/usr/local/lib/python3.9/dist-packages/usb/core.py", line 1029, in read
    ret = fn(
  File "/usr/local/lib/python3.9/dist-packages/usb/backend/libusb1.py", line 864, in intr_read
    return self.__read(self.lib.libusb_interrupt_transfer,
  File "/usr/local/lib/python3.9/dist-packages/usb/backend/libusb1.py", line 954, in __read
    _check(retval)
  File "/usr/local/lib/python3.9/dist-packages/usb/backend/libusb1.py", line 602, in _check
    raise USBTimeoutError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBTimeoutError: [Errno 110] Operation timed out
root@aquarium2:/opt# 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.