Skip to main content

Python library for controlling Jellyfish Lights via the local network.

Project description

Python wrapper for JellyFish Lights web socket API

Now available through pypi/pip!

To install:

pip install jellyfishlights-py

Current capabalilities

  • Connect to a local JellyFish Lighting controller over websocket
  • Retrieve the following data:
    • Controller's name, hostname, and firmware version
    • Timezone configuration
    • Zone configuration
    • Preset patterns and their configurations
    • Zone states
    • Calendar schedule
    • Daily schedule
  • Turn zones on and off
  • Activate a preset pattern
  • Set lights to a solid color with brightness control
  • Set any individual lights you want with brightness control
  • Activate a custom pattern configuration
  • Create, update, and delete custom pattern configurations
  • Create, update, and delete schedule events (calendar and daily)
  • Create, update, and delete zone configurations
  • Set the controller's name

Examples

The snippets below show most of what this module can do and have important usage notes in the comments.

Connectivity, logging, and basic controller information

from jellyfishlightspy import JellyFishController, ScheduleEvent, ScheduleEventAction, ZoneConfig, PortMapping
import logging

# Debug logging exposes the JSON messages sent to and received from the controller
logging.basicConfig(level = logging.DEBUG)

# Create a controller object and connect
jfc = JellyFishController('192.168.0.245') # hostname also works
jfc.connect()

# Print the controller's name and hostname
print(f"Connected to JellyFish Lighting controller '{jfc.name}' ({jfc.hostname})")

# Print the controller's firmware version information
print(f"Firmware version: {jfc.firmware_version}")

# Print the controller's timezone configuration
print(f"Timezone configuration: {jfc.time_config}")

# Change the controller's user-defined name
jfc.set_name("My JellyFish Controller")

# Disconnect from the controller
jfc.disconnect()

Listening for Push Events (connection status, messages, and errors)

# Create callbacks to respond to various events
def on_open()
  print("Connected!")

def on_close(status, message)
  print("Disconnected (status: %s, message: %s)", status, message)

def on_message(data)
  print("Recieved push data: %s", data)

def on_error(error)
  print("Error encountered: %s", error)

# Register your callbacks
jfc.add_listener(on_open, on_close, on_message, on_error)

Zones (state, turning on/off, and configuration)

# Print the currently configured zones
# NOTE: all attributes on the controller will return cached data when available.
# Cached data is automatically updated via push events, but if you want to ensure
# you are retrieving the latest information from the controller, use the corresponding
# get_* function (jfc.get_zone_names() in this case)
print(f"Zones: {jfc.zone_names}")

# Print the current state of all zones
for name, state in jfc.get_zone_states().items():
    pattern = state.file
    brightness = state.data.runData.brightness
    colors = state.data.colors
    print(f"Zone '{name}' is {'on' if state.is_on else 'off'} (pattern: '{pattern}', colors: {colors}, brightness: {brightness})")

# Turn off all zones
# NOTE: Many commands have an optional zones parameter. If not filled, it defaults to all zones
# NOTE: Many of the commands have an optional sync parameter.
# If sync=False (default is True) it sends the command and does not wait for a response (returns immediately)
jfc.turn_off(sync=False)

# Turn on the 'front-zone' zone - the lights will be in the same state as when they were last on
# NOTE: Many of the commands have an optional timeout parameter.
# If sync=True (it is by default), the command is synchronous and will raise a JellyFishException
# if a response isn't received within the timeout period (default is 10 seconds).
jfc.turn_on(["front-zone"], timeout=5)

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# !!ADVANCED!! - change zone configurations
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
orig_zones = jfc.zone_configs

# Print current zone configurations
for zone, config in orig_zones.items():
  print(f"Zone '{zone}' config: {config}")

# Add a new zone
new_config = ZoneConfig([
    # NOTE: the phyPort attribute maps as such to the ports on the controller (controller port->phyPort): 1->1, 2->2, 3->4, 4->8
    # NOTE: zoneRGBStartIdx defaults to phyStartIdx. Setting it to the phyEndIdx value will reverse the direction
    # NOTE: ctlrName defaults to the hostname of the controller you are currently connected to (jfc.hostname)
    # NOTE: All of the *Idx values are one less than what is displayed in the app! (e.g. a "1" value in the app is a "0" value here)
    PortMapping(phyPort=1, phyStartIdx=0, phyEndIdx=10, zoneRGBStartIdx=10, ctlrName="JellyFish-XXXX.local"),
    # NOTE: this is the short version that sets only the required fields: phyPort, phyStartIdx, and phyEndIdx
    PortMapping(2, 0, 99)
])
jfc.add_zone("My new zone", new_config)

# Delete the zone we just created
jfc.delete_zone("My new zone")

# Save the full set of all zone configurations at once
jfc.set_zone_configs({"My new zone": new_config}) # This would result in a single zone (any other zones would be deleted)
jfc.set_zone_configs({}) # This would delete all zone configurations
jfc.set_zone_configs(orig_zones) # This would restore the zone configurations to what we retrieved above (before we modified them)

Patterns

# Print the list of currently configured patterns
print(f"Patterns: {jfc.pattern_names}")

# Run a preset pattern on all zones
jfc.apply_pattern("Special Effects/Red Waves")

# Retrieve a pattern configuration
config = jfc.get_pattern_config("Colors/Blue")
print(config)

# Customize the pattern configuration and run it on the 'front-zone' zone
# (this example shows just a few of the configurable pattern attributes)
config.colors.extend([0, 0, 0]) # Note that 'colors' is a list of ints, not a list of tuples! Be sure the list is divisible by 3
config.type = "Chase" # Valid values: ["Color", "Chase", "Paint", "Stacker", "Sequence", "Multi-Paint", "Soffit"]
config.direction = "Center" # Valid values: ["Left", "Center", "Right"]
config.spaceBetweenPixels = 8
config.effectBetweenPixels = "Progression" # Valid values: ["No Color Transform", "Repeat", "Progression", "Fade", "Fill with Black"]
config.runData.speed = 1
config.runData.effect = "No Effect" # Valid values: ["No Effect", "Twinkle", "Lightning"]
jfc.apply_pattern_config(config, ["front-zone"])

# Save your new pattern to a file to easily run later.
# The parent folder will be created if it doesn't exist.
# You can also update existing patterns this way (if they're editable).
jfc.save_pattern("Special Effects/Blue Waves", config)

# Delete the pattern
jfc.delete_pattern("Special Effects/Blue Waves")

Manual light control

# Set 'front-zone' and 'back-zone' to a solid color (white @ 100% brightness in this case)
jfc.apply_color((255, 255, 255), 100, ["front-zone", "back-zone"])

# Set individual lights on the 'porch-zone' zone
# This example sets only the first 3 lights in the zone, but you can set as many as you would like
lights = [
    (255, 0, 0), # Red
    (0, 255, 0), # Green
    (0, 0, 255)  # Blue
]
jfc.apply_light_string(lights, 75, ["porch-zone"]) # 75% brightness

Schedules

# Retrieve the calendar schedule
orig_events = jfc.calendar_schedule # Use jfc.daily_schedule to get the daily schedule
for event in orig_events:
  print(event)

# Add an event to the schedule
event = ScheduleEvent(
    # Must be in YYYYMMDD format for calendar events
    # Even though a year must be specified the event will run annually
    # You must include each individual day if specifying a range
    days = ["20231231", "20230101", "20230102"],
    # days = ["M", "T", "W", "TH", "F", "SA", "S"], <-- Example for a daily schedule event
    actions = [
        ScheduleEventAction(
          type = "RUN",
          startFrom = "sunset",
          hour = 0, # For 'sunrise' and 'sunset', hour must be 0...
          minute = 30, # ...and the minute offset must be between -55 and 55 and divisible by 5
          patternFile = "Special Effects/Rainbow Waves",
          zones = jfc.zone_names # The list of zones for each RUN/STOP action must match!
        ),
        # For 'time', the hour must be between 0 and 23, and minute between 0 and 59
        ScheduleEventAction("STOP", "time", 5, 00, "", jfc.zone_names)
    ]
)
jfc.add_calendar_event(event)

# To remove events you must send the updated full schedule of events
jfc.set_calendar_schedule([event]) # This would delete all events other than what we just created
jfc.set_calendar_schedule([]) # This would delete all events
jfc.set_calendar_schedule(orig_events) # This would restore the schedule to what we retrieved above (before we modified it)

Contributing

Contributions are welcome! To run the test suite, first set the JF_TEST_HOST environment variable to your local JellyFish Lighting controller's address. Then run:

python -m pytest ./tests

If you don't have a local controller to test with you can skip the integration tests by running:

python -m pytest ./tests/unit

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jellyfishlights_py-0.8.1.tar.gz (18.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jellyfishlights_py-0.8.1-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file jellyfishlights_py-0.8.1.tar.gz.

File metadata

  • Download URL: jellyfishlights_py-0.8.1.tar.gz
  • Upload date:
  • Size: 18.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for jellyfishlights_py-0.8.1.tar.gz
Algorithm Hash digest
SHA256 95be7a694f6e11af6a592c8b2eb8ad36e0890de52394ccef259202687f9fc632
MD5 6fba1db5c98761907c6ab840d777ee27
BLAKE2b-256 db9cb4c9427fa4d8b2a95270ee4e7c1601704a62d0ef54c197773f3cf0514d52

See more details on using hashes here.

Provenance

The following attestation bundles were made for jellyfishlights_py-0.8.1.tar.gz:

Publisher: publish.yml on vinenoobjelly/jellyfishlights-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jellyfishlights_py-0.8.1-py3-none-any.whl.

File metadata

File hashes

Hashes for jellyfishlights_py-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 934c88f2716e2396a9b7bb13abd50df66a494cbd9e2acdeacacd7102b8bdae5e
MD5 f4f404981de99f5f4bdb045c5634abe1
BLAKE2b-256 b45974e5fd934140ae16a3001826e436ae93e352c867a096f6414b73e65b886a

See more details on using hashes here.

Provenance

The following attestation bundles were made for jellyfishlights_py-0.8.1-py3-none-any.whl:

Publisher: publish.yml on vinenoobjelly/jellyfishlights-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page