Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Pixelblaze backend #26

Merged
merged 2 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,16 @@ MariMapper support the following pre-made backends:
- `fadecandy`
- [`wled`](https://kno.wled.ge/)
- [`fcmega`](https://github.com/TheMariday/FC-Mega)
- [`pixelblaze`](https://electromage.com/docs)
- `custom`

If you choose a pre-built backend, remember to install its dependencies using
`pip install -r backends/fadecandy/requirements.txt`

When using Fadecandy, WLED, or Pixelblaze backends, pass the server IP or URI with the `--server` flag.

Using Pixelblaze as a backend requires you to upload the [`marimapper.epe`](backends/pixelblaze/marimapper.epe) pattern to your pixelblaze before running Marimapper.

However, your LEDs are as unique as you are,
so it's super simple to implemenet your own `custom` backend by filling in the blanks
in [backends/custom/custom_backend.py](backends/custom/custom_backend.py):
Expand Down
8 changes: 8 additions & 0 deletions backends/pixelblaze/marimapper.epe
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "marimapper",
"id": "GihLfEwy523cFgomM",
"sources": {
"main": "export var pixel_to_light = -1\nexport var turn_on=true\n\nexport function render(index) {\n if(index == pixel_to_light && turn_on){\n rgb(1,1,1)\n } else{\n rgb(0,0,0)\n }\n}"
},
"preview": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCACWAGQDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8qqACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP/Z"
}
10 changes: 10 additions & 0 deletions backends/pixelblaze/marimapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export var pixel_to_light = -1
export var turn_on=true

export function render(index) {
if(index == pixel_to_light && turn_on){
rgb(1,1,1)
} else{
rgb(0,0,0)
}
}
27 changes: 27 additions & 0 deletions backends/pixelblaze/pixelblaze_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pixelblaze


class Backend:

def __init__(self, pixelblaze_ip="4.3.2.1"):
self.pb = pixelblaze.Pixelblaze(pixelblaze_ip)
self.pb.setActivePatternByName(
"marimapper"
) # Need to install marimapper.js to your pixelblaze

def get_led_count(self):
pixel_count = self.pb.getPixelCount()
print(f"Pixelblaze reports {pixel_count} pixels")
return pixel_count

def set_led(self, led_index: int, on: bool):
self.pb.setActiveVariables({"pixel_to_light": led_index, "turn_on": on})

def set_map_coordinates(self, pixelmap: list):
result = self.pb.setMapCoordinates(pixelmap)
if result is False:
raise RuntimeError("Pixelblaze Backend failed to upload map coordinates.")
self.pb.wsSendJson({"mapperFit": 0})

def set_current_map(self, pixelmap_name: str):
self.pb.setActivePatternByName(pixelmap_name)
3 changes: 3 additions & 0 deletions backends/pixelblaze/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# This file defines the requirements for the Pixelblaze backend

pixelblaze-client
64 changes: 64 additions & 0 deletions backends/pixelblaze/upload_map_to_pixelblaze.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import argparse
import sys
import csv

sys.path.append("./")

from lib import utils


def read_coordinates_from_csv(csv_file_name):
print(f"Loading coordinates from {csv_file_name}")
with open(csv_file_name, newline="") as csvfile:
csv_reader = csv.DictReader(csvfile)
list_of_leds = []
for row in csv_reader:
list_of_leds.append(row)

# Find the largest index in the list
num_leds = int(max(list_of_leds, key=list_of_leds.index)["index"])

final_coordinate_list = []

for i in range(num_leds):
# Either find the list with the matching index
# or default to [0,0,0] if we never saw the pixel
coords = next(
(item for item in list_of_leds if int(item["index"]) == i),
{"x": 0, "y": 0, "z": 0},
)
final_coordinate_list.append(
[float(coords["x"]), float(coords["y"]), float(coords["z"])]
)

return final_coordinate_list


def main_function(cli_args):
final_coordinate_list = read_coordinates_from_csv(cli_args.csv_file)
print(final_coordinate_list)

upload_coordinates = utils.get_user_confirmation(
"Upload coordinates to Pixelblaze? [y/n]: "
)
if not upload_coordinates:
return

print(f"Uploading coordinates to pixelblaze {cli_args.server}")
led_backend = utils.get_backend("pixelblaze", cli_args.server)
led_backend.set_map_coordinates(final_coordinate_list)
print("Finished")


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Upload led_map_3d.csv to pixelblaze")
parser.add_argument("--server", type=str, help="pixelblaze server ip")
parser.add_argument(
"--csv_file",
type=str,
help="The csv file to convert",
default="my_scan/led_map_3d.csv",
)
args = parser.parse_args()

main_function(args)
7 changes: 6 additions & 1 deletion lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def add_backend_args(parser):
"--backend",
type=str,
help="The backend used for led communication",
choices=["custom", "fadecandy", "wled", "fcmega"],
choices=["custom", "fadecandy", "wled", "fcmega", "pixelblaze"],
required=True,
)

Expand Down Expand Up @@ -90,6 +90,11 @@ def get_backend(backend_name, server=""):

return fcmega_backend.Backend()

if backend_name == "pixelblaze":
from backends.pixelblaze import pixelblaze_backend

return pixelblaze_backend.Backend(server)

raise RuntimeError("Invalid backend name")

except NotImplementedError:
Expand Down