Skip to main content

Python wrapper for JellyFish Lights web socket API

Now available through pypi/pip!

To install:

pip install jellyfishlights-py

⚠️ Warning: Some data managed through this library (e.g. zone configurations, patterns, and schedules) is liable to be overwritten by the JellyFish cloud service if the controller is also connected to it. Changes you make locally may be reverted without warning when the controller syncs with the cloud.

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

Release files for jellyfishlights-py 0.8.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jellyfishlights-py 0.8.2
File Size Uploaded
jellyfishlights_py-0.8.2.tar.gz 18.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jellyfishlights-py 0.8.2
File Interpreter ABI Platform
jellyfishlights_py-0.8.2-py3-none-any.whl Python 3 none any Details

Total release size: 40.1 kB

Release files / jellyfishlights_py-0.8.2.tar.gz

Download URL jellyfishlights_py-0.8.2.tar.gz
Size 18.7 kB
Tags Source
SHA-256 checksum
How to use checksums
fa92cd403e000919e8cad7b64c41ca88c61996ceda99fb9bd161a3cf73ae26c6
BLAKE2b-256 checksum
How to use checksums
e383aa1071242e3fe65eb10af7c5ba0c227b265e951acf45a8f3f25789efc079
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 23, 2026.

Transparency log

Release files / jellyfishlights_py-0.8.2-py3-none-any.whl

Download URL jellyfishlights_py-0.8.2-py3-none-any.whl
Size 21.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
30203b3963a7fd883f01eb4ef042278c0805a05620550c312aec2acc5a23a7ad
BLAKE2b-256 checksum
How to use checksums
f2392bfe617c2b0efb342d810241a951956cdb64d0dab3a0a1ae2408aa553741
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 23, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.2 This release

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

1 release file

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.3

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page