Skip to content

Instantly share code, notes, and snippets.

@brunopk
Last active March 6, 2024 01:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brunopk/b7a69f04c7ceb47518ae0698f691f66e to your computer and use it in GitHub Desktop.
Save brunopk/b7a69f04c7ceb47518ae0698f691f66e to your computer and use it in GitHub Desktop.
Strip Controller

Strip Controller

Ideas for the whole system

  • Send broadcast messages from sc-master to detect available devices so users don't need to know IP addresses and ports.
  • Multiple devices.
  • Device and master (sc-master) metrics:
    • Measure how much time takes to change color for all lights:
      • Considering sc-web-sc-master-sc-rpi and/or sc-master-sc-rpi
      • It should be 60 FPS ( no more than 1/60 seconds).
    • CPU, memory, network, request/response times, etc.
    • Investigate best approach:
      • Implemented as sc-master RESTful endpoints (disadvantage: coupled to sc-master, advantage:maybe easier to implement).
      • Separated from web server provided by DRF (advantage: decoupled from sc-master, see PCP).
    • Displayed as graphics in sc-web or separated (see RabbitMQ)
  • Deploy all with Docker. For example, sc-master and sc-web in the same container. It may be specially useful to dockerize it when implementing metrics in a decoupled way as mentioned above, the metric system may run in a different container.
  • Different modes, specially useful when having multiple devices:
    • FUSIONED: all strips are viewed as one, so for example instead of controlling two strips each one with 300 leds, it can be viewed as one strip of size 600 working as one.
    • SEPARATED: almost the opposite of FUSIONED.
  • Improve README.md for all components:
    • Summarize and separate specific content in smaller markdown files.
    • Provide a short description of what SC is (the same description for all components) in addition to current description of what the component is intended for and how to run it, no much more than this.
  • Allow section editions which changes the order. For instance, having sections [4, 8] and [9, 10], allow editing the second section to [1, 2] (analyze if it could generate future issues before doing code changes).
  • Provide a mechanism to synchronize sc-master with sc-rpi. For instance, if for sc-master leds are turned off and for sc-rpi they are turned on (for instance sc-master lost connection with sc-rpi just after turning leds off leading to the missmatch). This could be managed, with a periodic process to coordinates the state of both components, or just after sc-master try to invoke a specific command on sc-rpi.

Ideas for sc-web

  • Traduction file

  • Improve font-size definition to avoid issues with em and rem units (for example define font-size in html tag and use only rem).

  • Display sc-master server logs (generated by DRF) on the frontend. It may be better to include more attributes on sc-master command responses. For example when executing a /turn_on command on sc-master, the output could be something like this :

    {
      "code": "SC_RPI_ERROR",
      "device_name": "raspberry",
      "command": "turn_on"
      "status": 400
    }

    where the 400 indicates the status returned by raspberry after executing the turn_on (sc-rpi) command (think of trying to turn on more than one device, raspberry and raspberry2 by executing the turn_on for both devices).

  • Send raw commands (as stringified JSONs) directly to sc-rpi.

src/stores/RootStore.ts

  • Scan stores in all src/pages/* instead of manually adding them as instance attributes in RootStore class.

Ideas for sc-rpi

  • Display some lighting effect after establishing a connection between sc-master and sc-rpi in order to quickly visualize if the connection was established correctly. DONE
  • Add an environment for development (it should not use the rpi_ws281x module which is only for Raspberry) DONE
  • Avoid systemd excesive retries to run the server, it seems recommendations on Stack Overflow doesn't work.
  • Send domain name with mDNS to avoid setting IP address.
  • Log received raw command when there's a parse error.
  • Log all commands in DEBUG level.
  • Turning section on should turn that section on despite all strip was turned off before.

scripts/upload.sh

Use rsync to avoid uploading and replacing files. DONE

Ideas for sc-master

  • Avoid using the prefix System for error classes.
  • Avoid using the prefix System for error classes.
  • Provide a mechanism to obtain DRF logs, for example DRF file logs can be exposed with an nginx server.
  • Give devices a name defined by user.
  • Write automatic test.
  • In order to support different modes as mentioned in "Ideas for the whole system", use adapter pattern, for instance having three classes : DeviceController, SectionController and StaticModeController which will play the role of adapter between DeviceController and SectionController.

commands/urls.py

  • Move commands in the {{baseUrl}}/commands/system/* path to just {{baseUrl}}/commands/*

sc_master/controllers/device_controller.py

  • Try to avoid repeating the final return cls._build_result() in all methods
  • Evaluate not using class methods. First thing to take into account is concurrency requirements, It means, if Python and Django Rest Framework capabilities (when and how It start new threads in order to support concurrency), It may be bad idea to use class methods. On the other hand, and if the system is intended to support only one user, It won't matter.
  • Avoid using the prefix System for error classes.
  • Currently the code is intended for controlling one device, so when extending the system to control more than one device, the handle_device_client_errors decorator could handle errors from any of these devices. For example, if an error occurs on device d1 (considering devices d1 and d2), this method could identify from which device the error comes from and set an specific attribute on the final Result object indicating that d2 continues working as expected but d1 had an error on the last operation.
  • Currently, in case of error when sending commands to a device, an error response will be returned. After extending the system as mentioned above, this approach may not be appropiated. Think the scenario that you have two devices d1 and d2 and only one of them fails. From the API perspective, it can be viewed as a request that should return HTTP 207 code (MULTI-STATUS) with the corresponding JSON instead of an error response like {"code": xxxx, "message": "error"} with status 500.
  • After catching BrokenPipe, for instance after abtuptly disconnecting sc-rpi, and trying to send another command, the connected device remains inconsitently on sc-master. A good approach may be to run a periodic task with Django which cleans resources on this situations.

sc_master/utils/decorators.py

  • Use logger.error(ex) instead of logger.error(ex.traceback()) to avoid logging too much error info. DONE

File: sc-master/commands/serializers/sections/add.py:

  • The sections attribute is not being validated when it's an empty list or even when it is not present on endpoint body:
{
  "sections": []
}

The same situations may be happening for all endpoint (serializers) which uses lists for request body.

Bugs

  • When connecting more than once to the same device, sc-master and sc-rpi seems to hang. Comment out this lines on sc_master/controllers/device_controller.py:

      if cls._device is not None:
        raise ApiError(ErrorCode.SY_DEVICE_ALREADY_CONNECTED)

    to reproduce bug.

Bugs on sc-rpi

  • Investigate why service is not properly stopping when there's an active connection:

    Mar 05 20:20:40 raspberrypi systemd[1]: Stopping sc-rpi server...
    Mar 05 20:22:11 raspberrypi systemd[1]: sc-rpi.service: State 'stop-sigterm' timed out. Killing.
    Mar 05 20:22:11 raspberrypi systemd[1]: sc-rpi.service: Killing process 830 (python) with signal SIGKILL.
    Mar 05 20:22:11 raspberrypi systemd[1]: sc-rpi.service: Main process exited, code=killed, status=9/KILL
    Mar 05 20:22:11 raspberrypi systemd[1]: sc-rpi.service: Failed with result 'timeout'.
    Mar 05 20:22:11 raspberrypi systemd[1]: Stopped sc-rpi server.
    
    • When sending not existent section returns 500 instead of 404:
      {
        "status": 500,
        "description": "No message",
        "data": null
      }
  • Strip starts turned on, but after executing turn_off command the response say its turned off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment