This commit is contained in:
BlueOceanWave 2024-04-12 20:28:33 -05:00
commit 4973fc79be
11 changed files with 183 additions and 85 deletions

3
.gitmodules vendored Normal file

@ -0,0 +1,3 @@
[submodule "jukebox-web"]
path = jukebox-web
url = https://git.myitr.org/Jukebox/jukebox-web

@ -3,11 +3,11 @@ FROM python:3.11-slim
# Get runtime dependencies
# glx for OpenCV, ghostscript for datasheet PDF rendering, zbar for barcode scanning, git for cloning repos
RUN apt-get update && apt-get install -y libgl1-mesa-glx ghostscript libzbar0 git && apt-get clean && rm -rf /var/lib/apt/lists
COPY *.py *.yml *.sh *.txt *.html static templates ./
COPY requirements.txt ./
#COPY config-server.yml config.yml
RUN pip3 install -r requirements.txt
CMD ["python3", "run.py"]
COPY *.py *.yml *.sh *.txt *.html static templates ./
CMD ["sh", "-c", "python3 run.py"]
EXPOSE 5000
EXPOSE 8000
EXPOSE 9000

13
compose-search-only.yml Normal file

@ -0,0 +1,13 @@
services:
meilisearch:
image: "getmeili/meilisearch:v1.6.2"
ports:
- "7700:7700"
environment:
MEILI_MASTER_KEY: fluffybunnyrabbit
MEILI_NO_ANALYTICS: true
volumes:
- "meili_data:/meili_data"
volumes:
meili_data:

@ -8,6 +8,23 @@ services:
MEILI_NO_ANALYTICS: true
volumes:
- "meili_data:/meili_data"
jukebox-software:
build: .
init: true
ports:
- "5000:5000"
- "8000:8000"
- "9000:9000"
environment:
- PYTHONUNBUFFERED=1
depends_on:
- meilisearch
jukebox-web:
build: jukebox-web
ports:
- "3000:3000"
volumes:
meili_data:

@ -344,9 +344,13 @@ def get_multi(partnums, delay=0.25, dir="cables/", cache=True, bar=None):
fprint("Using cached hi-res part image for " + partnum)
out = __use_cached_datasheet(partnum, path, output_dir, dstype)
returnval = [partnum, dstype, False, out]
actualpartnums.append(returnval)
return True
for fullpartnum in partnums:
if fullpartnum is False:
actualpartnums.append(False)
continue
if fullpartnum[0:2] == "BL": # catalog.belden.com entry
partnum = fullpartnum[2:]
dstype = "Belden"

1
jukebox-web Submodule

@ -0,0 +1 @@
Subproject commit f3d8ec0cc421cb8f8b7bb4b30339f3663f70b297

@ -301,7 +301,7 @@ def parse(filename, output_dir, partnum, dstype):
output_table["id"] = id
#output_table["position"] = id
#output_table["brand"] = brand
output_table["fullspecs"] = tables
output_table["fullspecs"] = {"partnum": partnum, "id": id, **tables}
output_table["searchspecs"] = {"partnum": partnum, **flatten(tables)}
output_table["searchspecs"]["id"] = id

187
run.py

@ -26,7 +26,7 @@ import json
import process_video
import search
from search import JukeboxSearch
#multiprocessing.set_start_method('spawn', True)
config = None
@ -90,7 +90,15 @@ def wait_for(val, name):
while val is False:
sleep(0.1)
def start_server_socket():
def send_data(type, call, data, client_id="*"):
out = dict()
out["type"] = type
out["call"] = call
out["data"] = data
to_server_queue.put((client_id, json.dumps(out)))
def start_server_socket(cable_list):
global jbs
"""app = Flask(__name__)
@app.route('/report_ip', methods=['POST'])
@ -122,69 +130,92 @@ def start_server_socket():
# Message handler
try:
decoded = json.loads(message)
if "type" not in decoded:
fprint("Missing \"type\" field.")
continue
if "call" not in decoded:
fprint("Missing \"call\" field.")
continue
if "data" not in decoded:
fprint("Missing \"data\" field.")
continue
except:
fprint("Non-JSON message recieved")
continue
# if we get here, we have a "valid" data packet
data = decoded["data"]
call = decoded["call"]
if "type" not in decoded:
fprint("Missing \"type\" field.")
continue
if "call" not in decoded:
fprint("Missing \"call\" field.")
continue
if "data" not in decoded:
fprint("Missing \"data\" field.")
continue
# if we get here, we have a "valid" data packet
data = decoded["data"]
call = decoded["call"]
try:
match decoded["type"]:
case "log":
fprint("log message")
if call == "send":
fprint("webapp: " + str(data), sendqueue=to_server_queue)
elif call == "request":
fprint("")
pass
case "cable_map":
fprint("cable_map message")
if call == "send":
fprint("")
pass
elif call == "request":
fprint("")
tmp = list()
for idx in range(len(cable_list)):
if cable_list[idx] is not False:
tmp1 = {"part_number": cable_list[idx], "position": idx, "name": cable_list[idx], "brand": "Belden", "description": "Blah", "short_description": "Bla"}
tmp.append(tmp1)
out = {"map": tmp}
fprint(out)
send_data(decoded["type"], "send", out, client_id)
case "ping":
fprint("Pong!!!")
# Lucas' notes
# Add a ping pong :) response/handler
# Add a get cable response/handler
# this will tell the robot arm to move
# Call for turning off everything
# TODO Helper for converting Python Dictionaries to JSON
# make function: pythonData --> { { "type": "...", "call": "...", "data": pythonData } }
# to send: to_server_queue.put(("*", "JSON STRING HERE")) # replace * with UUID of client to send to one specific location
case "cable_details":
fprint("cable_details message")
if call == "send":
fprint("")
pass
elif call == "request":
fprint("")
dataout = dict()
dataout["cables"] = list()
print(data)
if "part_number" in data:
for part in data["part_number"]:
#print(part)
#print(jbs.get_partnum(part))
dataout["cables"].append(jbs.get_partnum(part)["fullspecs"])
if "position" in data:
for pos in data["position"]:
#print(pos)
#print(jbs.get_position(str(pos)))
dataout["cables"].append(jbs.get_position(str(pos))["fullspecs"])
send_data(decoded["type"], "send", dataout, client_id)
case "cable_search":
fprint("cable_search message")
if call == "send":
fprint("")
pass
elif call == "request":
fprint("")
results = jbs.search(data["string"])["hits"]
dataout = dict()
dataout["cables"] = list()
for result in results:
dataout["cables"].append(result["fullspecs"])
send_data(decoded["type"], "send", dataout, client_id)
case "keyboard":
fprint("keyboard message")
if call == "send":
fprint("")
pass
elif call == "request":
fprint("")
if data["enabled"] == True:
# todo : send this to client
p = Process(target=run_cmd, args=("./keyboard-up.ps1",))
@ -192,21 +223,19 @@ def start_server_socket():
elif data["enabled"] == False:
p = Process(target=run_cmd, args=("./keyboard-down.ps1",))
p.start()
case "machine_settings":
fprint("machine_settings message")
if call == "send":
fprint("")
pass
elif call == "request":
fprint("")
pass
case _:
fprint("Unknown/unimplemented data type: " + decoded["type"])
except Exception as e:
fprint(traceback.format_exc())
fprint(e)
except:
fprint("Non-JSON message recieved")
continue
sleep(0.001) # Sleep to prevent tight loop
@ -262,8 +291,8 @@ def setup_server(pool):
ledsys = LEDSystem()
pool.apply_async(ledsys.init, callback=led_start_callback)
#pool.apply_async(sensor_control.init, callback=sensor_start_callback)
serverproc = Process(target=start_server_socket)
serverproc.start()
jbs = JukeboxSearch()
if led_ready is False:
@ -293,7 +322,7 @@ def setup_server(pool):
fprint("Arm initialized.", sendqueue=to_server_queue)
jbs = JukeboxSearch()
return True
@ -338,9 +367,12 @@ def mainloop_server(pool):
elif camera_ready:
fprint("Adding cable to list...")
global scan_value
if scan_value.find("bldn.app/") > -1:
if scan_value is False:
cable_list.append(scan_value)
elif scan_value.find("bldn.app/") > -1:
scan_value = scan_value[scan_value.find("bldn.app/")+9:]
cable_list.append((counter, scan_value))
else:
cable_list.append(scan_value)
fprint(scan_value)
#pool.apply_async(arm.return cable, callback=arm_start_callback)
arm_state = "RETURN"
@ -354,19 +386,8 @@ def mainloop_server(pool):
pass
else:
# scanned everything
tmp = list()
for cable in cable_list:
tmp.append(cable[1])
tmp = [
# Actual cables in Jukebox
"AW86104CY",
"AW3050",
"AW6714",
"AW1172C",
"AWFIT-221-1_4",
"BLTF-1LF-006-RS5",
"BLTF-SD9-006-RI5",
"BLTT-SLG-024-HTN",
@ -388,10 +409,17 @@ def mainloop_server(pool):
"BL8760",
"BL6300UE",
"BL6300FE",
"BLRA500P"
"BLRA500P",
"AW86104CY",
"AW3050",
"AW6714",
"AW1172C",
"AWFIT-221-1_4"
]
cable_list = tmp
pool.apply_async(get_specs.get_multi, (tmp, 0.5), callback=cable_search_callback)
while len(tmp) < 54:
tmp.append(False) # must have 54 entries
cable_list = tmp # remove for real demo
pool.apply_async(get_specs.get_multi, (tmp, 0.3), callback=cable_search_callback)
mode = "Parsing"
fprint("All cables scanned. Finding & parsing datasheets...")
if mode == "Parsing":
@ -403,29 +431,35 @@ def mainloop_server(pool):
# done
global parse_res
success, partnums = parse_res
#partnums = list()
# debug
#success = True
for idx in range(len(partnums)):
if partnums[idx] is not False:
cable_list[idx] = partnums[idx][0].replace("/", "_")
else:
cable_list[idx] = False
#cable_list = list(range(len(partnums)))
print(partnums)
if success:
# easy mode
fprint("All cables inventoried and parsed.")
for x in range(len(cable_list)):
#cable_list[x] = (cable_list[x][0], partnums[x])
cable_list[x] = (x, cable_list[x])
fprint("Adding to database...")
for idx,partnum in cable_list:
with open("cables/" + partnum[2:] + "/search.json", "rb") as f:
searchdata = json.load(f)
searchdata["position"] = idx
with open("cables/" + partnum[2:] + "/specs.json", "rb") as f:
specs = json.load(f)
searchdata["fullspecs"] = specs
jbs.add_document(searchdata)
for idx in range(len(cable_list)):
partnum = cable_list[idx]
if partnum is not False:
with open("cables/" + partnum + "/search.json", "rb") as f:
searchdata = json.load(f)
searchdata["position"] = idx
with open("cables/" + partnum + "/specs.json", "rb") as f:
specs = json.load(f)
searchdata["fullspecs"] = specs
searchdata["fullspecs"]["position"] = idx
jbs.add_document(searchdata)
#sleep(0.5)
#print(jbs.get_position("1"))
fprint("All cables added to database.")
mode = "Idle"
serverproc = Process(target=start_server_socket, args=(cable_list,))
serverproc.start()
else:
# TODO: manual input
pass
@ -562,7 +596,7 @@ if __name__ == "__main__":
with open('config.yml', 'r') as fileread:
#global config
config = yaml.safe_load(fileread)
fprint("Config loaded.")
with Manager() as manager:
fprint("Spawning threads...")
pool = LoggingPool(processes=10)
@ -583,5 +617,12 @@ if __name__ == "__main__":
fprint("Entering main loop...")
while(keeprunning):
mainloop_server(pool)
else:
fprint("Mode unspecified - assuming server")
fprint("Starting in server mode.")
if setup_server(pool):
fprint("Entering main loop...")
while(keeprunning):
mainloop_server(pool)

@ -6,7 +6,7 @@ from meilisearch.task import TaskInfo
from meilisearch.errors import MeilisearchApiError
import time
DEFAULT_URL = "http://localhost:7700"
DEFAULT_URL = "http://127.0.0.1:7700"
DEFAULT_APIKEY = "fluffybunnyrabbit" # I WOULD RECOMMEND SOMETHING MORE SECURE
DEFAULT_INDEX = "cables"
DEFAULT_FILTERABLE_ATTRS = ["partnum", "uuid", "position"] # default filterable attributes
@ -70,11 +70,10 @@ class JukeboxSearch:
:param filterables: List of all filterable attributes"""
existing_filterables = self.idxref.get_filterable_attributes()
if len(set(existing_filterables).difference(set(filterables))) > 0:
taskref = self.idxref.update_filterable_attributes(filterables)
self.client.wait_for_task(taskref.index_uid)
#existing_filterables = self.idxref.get_filterable_attributes()
#if len(set(existing_filterables).difference(set(filterables))) > 0:
taskref = self.idxref.update_filterable_attributes(filterables)
#self.client.wait_for_task(taskref.index_uid)
def search(self, query: str, filters: str = None):
"""Execute a search query on the Meilisearch index.
@ -95,7 +94,7 @@ class JukeboxSearch:
:returns: A dict containing the results; If no results found, an empty dict."""
q = self.search("", filter)
if q["estimatedTotalHits"] != 0:
return ["hits"][0]
return q["hits"][0]
else:
return dict()

20
setup-alpine-vm.sh Normal file

@ -0,0 +1,20 @@
#!/bin/sh
# This script must run as root!
echo "https://dl-cdn.alpinelinux.org/alpine/latest-stable/main
https://dl-cdn.alpinelinux.org/alpine/latest-stable/community" > /etc/apk/repositories
apk upgrade
apk add git docker docker-cli-compose
rc-update add docker
service docker start
git clone https://git.myitr.org/Jukebox/jukebox-software
cd jukebox-software
git submodule init
git submodule update
docker compose build
docker compose up -d

@ -81,7 +81,7 @@
socket.send(message);
console.log('Message sent', message);
}
setInterval(ping, 1500);
//setInterval(ping, 1500);
// setInterval(() => {
// updateServiceStatus('serviceA', 'down');