Skip to content

Commit

Permalink
Create Pixelblaze backend (#26)
Browse files Browse the repository at this point in the history
* Create Pixelblaze backend
---------

Co-authored-by: Samuel <martinsa0182@gmail.com>
  • Loading branch information
savdb and TheMariday committed Jul 12, 2024
1 parent cd18d6c commit aeb87a3
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 1 deletion.
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

0 comments on commit aeb87a3

Please sign in to comment.