minor changes and fixes, adjusted frontend

This commit is contained in:
katsu 2025-06-26 14:14:19 +02:00
parent d00651a66c
commit acc38950e7
11 changed files with 99 additions and 121 deletions

View file

@ -1,7 +1,7 @@
P01:
hosts:
10.32.50.170:
#192.168.192.42
#10.32.50.170:
192.168.192.42
vars:
static_ip: 192.168.192.42
static_mask: 24

View file

@ -101,7 +101,7 @@
become: true
ansible.builtin.systemd_service:
name: mosquitto.service
state: started
state: restarted
daemon_reload: true
@ -121,7 +121,7 @@
ansible.builtin.systemd_service:
name: "{{item}}"
enabled: true
state: started
state: restarted
loop:
- barco@main.service
- barco@side.service
@ -139,7 +139,7 @@
ansible.builtin.systemd_service:
name: projector_motors.service
enabled: true
state: started
state: restarted
- name: template tse serial box service
when: tse_box is defined
@ -154,7 +154,7 @@
ansible.builtin.systemd_service:
name: tse_box.service
enabled: true
state: started
state: restarted
- name: template lucke service
when: lucke is defined
@ -169,26 +169,7 @@
ansible.builtin.systemd_service:
name: lucke.service
enabled: true
state: started
# - name: Copy barco config
# become: true
# ansible.builtin.copy:
# #seuser: root
# src: "./{{ item }}"
# dest: /lib/systemd/system
# owner: root
# group: root
# mode: '0644'
# #backup: yes
# loop:
# - barco@.service
# #- extron_audio.service
# # - mqtt_init.service
# - projector_motors.service
# # - tse_box.service
state: restarted
@ -203,14 +184,7 @@
mode: '0644'
backup: yes
# - name: set env
# become: true
# ansible.builtin.lineinfile:
# dest: "/etc/environment"
# state: present
# regexp: "^{{ item.key }}="
# line: "{{ item.key }}={{ item.value }}"
# with_items: "{{ os_environment }}"
- name: copy frontend to webroot
become: true
@ -227,18 +201,3 @@
mode: '0755'
backup: yes
# - name: enable modules
# become: true
# ansible.builtin.systemd_service:
# #name: "{{[ 'barco@main.service', 'barco@side.service' ]}}"
# name: "{{ item }}"
# state: stopped
# enabled: false
# loop:
# - barco@main.service
# - barco@side.service
# # - extron_audio.service
# # - mqtt_init.service
# - projector_motors.service
# # - tse_box.service

View file

@ -7,12 +7,12 @@ import sys
#GLOBALS
room = "undefined"
position = "glavni"
barcoIP = "undefined"
telnetPort = 3023
mqttPort = 1883
mqttIP = 'localhost'
room: str
barcoPosition: str
barcoIP: str
telnetPort: int
mqttPort: int
mqttIP: str
cmdMap = {
'power': 'POWR',
@ -23,11 +23,11 @@ reverseCmdMap = {v: k for k, v in cmdMap.items()}
def parse_barco_response(raw: str):
global room, position
global room, barcoPosition
raw = raw[1:-1] # strip square brackets
#print(raw)
if raw.startswith("ERR"):
print("Projector" + room + " " + position + " returned" + raw)
print("Projector" + room + " " + barcoPosition + " returned" + raw)
return None # TODO parse type error - "disabled control" is special case which shouldnt normally happen
cmd, status = raw.split("!", maxsplit=2)
#print(cmd + " " + status)
@ -40,7 +40,7 @@ async def barco_telnet_command(client, writer, select: str):
global room
onSub = f"{room}/projectors/{select}/#"
#print('TEST', onSub)
onMatch = f"{room}/projectors/{select}/command/+"
onMatch = f"{room}/projectors/{select}/command/+" #TODO should be set?
await client.subscribe(onSub)
#async with client.messages as msgs:
async for mesg in client.messages:
@ -66,7 +66,7 @@ async def barco_telnet_read_status(client, reader, select: str):
raw_response: str = output.decode().strip() # strip not necessary? needed for local netcat testing though
print("Received: " + raw_response + " from Barco (" + select + ')')
parsed = parse_barco_response(raw_response)
if parsed == None:
if parsed is None:
continue #TODO alert for errors
print(f"Updating topic [{parsed[0]}] with value [{parsed[1]}]")
await client.publish(f"{room}/projectors/{select}/status/{parsed[0]}", payload=parsed[1])
@ -79,7 +79,7 @@ async def barco_telnet_query_status(writer, select: str):
writer.write(f"[{val}?]" + '\r\n') # TODO test if funny CRLF necessary (it probably gets ignored)
await asyncio.sleep(0.2) # sleep between writes necessary, otherwise it gets confused.
# simultaneous commands from control could break this? TODO fix later
await asyncio.sleep(30) # TODO find appropriate period
await asyncio.sleep(10) # TODO find appropriate period
# async def shell(reader, writer):
@ -102,8 +102,11 @@ async def main():
g62Barcos = {k: v for k,v in conf["barco_G62"].items()}
currentBarco = g62Barcos[barcoPosition]
barcoIP = currentBarco['ip']
telnetPort = currentBarco["port"]
room = conf["global"]["room"]
mqttPort = conf["global"]["mqttPort"]
mqttIP = conf["global"]["mqttIp"]
barcoReader, barcoWriter = await telnetlib3.open_connection(barcoIP, telnetPort)
async with aiomqtt.Client(mqttIP, mqttPort) as client:

View file

@ -27,9 +27,12 @@ function lockServicePage() {
}
//TODO display none namest uno
</script>
<template>
<div style="">
<div v-if="currentRoom == 'none'">
<h1>Incorrect or missing room parameter!</h1>
</div>
@ -48,19 +51,24 @@ function lockServicePage() {
</VerticalTabs>
<large style="display: flex;">turbo odličen super mega kontrol panel</large>
</header>
<main>
<MainPage v-if="pageNum == 0" :room="currentRoom" />
<VideoPage v-else-if="pageNum == 1" :room="currentRoom" />
<main style="flex-grow: 1">
<MainPage :class="{'hiddenPage': pageNum != 0}" :room="currentRoom" />
<VideoPage :class="{'hiddenPage': pageNum != 1}" :room="currentRoom" />
<LightingPage v-else-if="pageNum == 3" :room="currentRoom" />
<LightingPage :class="{'hiddenPage': pageNum != 3}" :room="currentRoom" />
<ServisPage v-else-if="pageNum == 4" :room="currentRoom" />
<ServisPage :class="{'hiddenPage': pageNum != 4}" :room="currentRoom" />
</main>
</div>
</div>
</template>
<style scoped>
.hiddenPage {
display: none !important
}
#wrapper {
width: 100%;
height: 100%;

View file

@ -42,7 +42,7 @@ function handleIncStatus(typ: string, msg: string) {
//console.log(projStatus)
if (typ == 'power') { roomStatus.proj_power = msg == '1' }
else if (typ == 'platno') { roomStatus.platno_state = msg }
else if (typ == 'lift') { roomStatus.lift_state = msg }
//else if (typ == 'lift') { roomStatus.lift_state = msg }
}
onMounted(() => {
@ -73,12 +73,12 @@ async function setLecture(pos?: String) {
} // else if (roomState.value == 1) {
// command = '0'
// } else { return }
publishMQTTMsg((topicPref + 'set/power'), command)
publishMQTTMsg((topicPref + 'command/power'), command)
publishMQTTMsg((topicPref + 'platno/goto'), command == '1' ? 'DOWN' : 'UP')
publishMQTTMsg((topicPref + 'lift/move/' + (command == '1' ? 'down' : 'up') ), '1')
publishMQTTMsg((topicPref + 'lift/move/' + (command == '1' ? 'down' : 'down') ), '1')
await sleep(1000)
publishMQTTMsg((topicPref + 'platno/goto'), 'STOP')
publishMQTTMsg((topicPref + 'lift/move/' + (command == '1' ? 'down' : 'up') ), '0')
// publishMQTTMsg((topicPref + 'platno/goto'), 'STOP')
publishMQTTMsg((topicPref + 'lift/move/' + (command == '1' ? 'down' : 'down') ), '0')
}
@ -87,7 +87,7 @@ async function setLecture(pos?: String) {
const roomStatus = reactive({
proj_power: false,
lift_state: 'UNKNOWN',
//lift_state: 'UNKNOWN',
platno_state: 'UNKNOWN',
})
@ -98,9 +98,9 @@ const roomState = ref(0)
watch (roomStatus, (_, _newState) => {
if (!_newState) { return }
let allOn = _newState.proj_power && _newState.platno_state == 'DOWN' && _newState.lift_state == 'DOWN'
let allOff = !_newState.proj_power && _newState.platno_state == 'UP' && _newState.lift_state == 'UP'
let anyUnknown = _newState.lift_state == 'UNKNOWN' || _newState.platno_state == 'UNKNOWN'
let allOn = _newState.proj_power && _newState.platno_state == 'DOWN' //&& _newState.lift_state == 'DOWN'
let allOff = !_newState.proj_power && _newState.platno_state == 'UP' //&& _newState.lift_state == 'UP'
let anyUnknown = _newState.platno_state == 'UNKNOWN'
if (allOn) {
roomState.value = 1
} else if (allOff) {
@ -130,7 +130,7 @@ watch (roomStatus, (_, _newState) => {
</div>
<h6>Projektor status: {{ roomStatus.proj_power ? "ON" : "OFF" }}</h6>
<h6>Platno pozicija: {{ roomStatus.platno_state }}</h6>
<h6>Dvigalo pozicija: {{ roomStatus.lift_state }}</h6>
<!-- <h6>Dvigalo pozicija: {{ roomStatus.lift_state }}</h6>-->
</div>
</template>

View file

@ -26,7 +26,7 @@ const MasterStatus = ref(false)
function handleIncomingMQTT(topic: string, msg: string) {
console.log('Received on', topic, 'with message', msg)
audioStatus.value = msg == '1'
MasterStatus.value = msg == '1'
}
onMounted(() => {
@ -43,7 +43,7 @@ function publishMQTTMsg(topic: string, msg: string) {
}
async function setMaster() {
let topicPref = props.room + "/power/audio/set"
let topicPref = props.room + "/power/master/set"
let command = '0'
if (!MasterStatus.value) {
command = '1'

View file

@ -88,9 +88,7 @@ const publishPrefix = ref(props.room + '/')
</script>
<template>
<div style="display: flex; gap: 1rem">
</div>
<div>
<div style="display:flex; gap: 1rem">
<div>
<h4>Firanki</h4>
@ -117,6 +115,7 @@ const publishPrefix = ref(props.room + '/')
<button :class="{currentlySelectedPreset: (lastPreset == '9')}" @click="publishMQTTMsg(publishPrefix + 'lucke/preset/recall', 'F')"A>Plchldr F</button>
</div>
</div>
</div>
</template>
<style scoped>

View file

@ -29,8 +29,6 @@ let _stranski = ref('side')
<h4>Stranski:</h4>
<LectureModule :room="props.room" :position="_stranski" />
</div>
</div>
<div>
<AudioControlModule :room="props.room" />
</div>
</template>

View file

@ -5,7 +5,7 @@ import asyncio
import toml
import aiohttp
lucke_bearer_token = ""
lucke_bearer_token = "" #TODO only set types
room = ""
url = ""
roomId = 0
@ -30,14 +30,14 @@ async def task_luckeCommand(controlClient):
msgTopicArr = mesg.topic.value.split('/')
sceneNum = mesg.payload.decode()
print("Received: " + str(msgTopicArr) + " payload: [" + sceneNum + "]")
print('sending request to endpoint..')
#print('sending request to endpoint..')
await sendSceneRequest(controlClient, sceneNum)
await asyncio.sleep(0.01)
async def main():
global room, lucke_bearer_token, url, roomId
conf = toml.load('./malinaConfig.toml')
room = conf.get("global")['room']
room = conf.get("global")['room'] #TODO use brackets everywhere (also other files)
url = conf.get("lucke")['url']
roomId = conf.get("lucke")['roomId']
lucke_bearer_token = conf.get("lucke")['bearer_token']

View file

@ -16,7 +16,7 @@ import toml
#relays = [LED(17), LED(27), LED(22), LED(23), LED(5), LED(6), LED(24), LED(25)]
main_I2C_addr = 0 #default
side_I2C_addr = 0
side_I2C_addr = 0 #TODO get actual projector motor things from config (dont hardcode main/side)
room = ""
use_offset = False
@ -90,15 +90,15 @@ async def task_command2relays(controlClient: aiomqtt.Client):
msgs = controlClient.messages
async for mesg in msgs:
mesg: aiomqtt.Message
if mesg.topic.matches(f'{room}/projectors/+/lift/move/#'):
if mesg.topic.matches(f'{room}/projectors/+/lift/move/+'):
msgTopicArr = mesg.topic.value.split('/')
state = mesg.payload.decode()
print("Received: " + str(msgTopicArr) + " payload: [" + state + "]")
#testCase = (msgTopicArr[2], msgTopicArr[4])
projSel = msgTopicArr[2]
projSel = msgTopicArr[2] #TODO projselect odzadaj indexed (just works tm)
if projSel != 'main' and projSel != 'side':
continue #TODO error hnadling?
command = msgTopicArr[5]
command = msgTopicArr[5] #TODO same
await msgRelayBoard(projSel, command, state == '1')
await controlClient.publish(f'{room}/projectors/{projSel}/lift/status', payload="", qos=1, retain=True)
#print("Pushing \'off\' to other relays to prevent conflicts")
@ -113,7 +113,7 @@ async def main():
mainMotor = projMotors.get("main")
sideMotor = projMotors.get("side")
main_I2C_addr = mainMotor['i2c_address']
side_I2C_addr = sideMotor['i2c_address']
side_I2C_addr = sideMotor['i2c_address'] #TODO spremen v dict
room = conf["global"]["room"]

View file

@ -24,7 +24,7 @@ if len(portList) < 1:
sys.exit("No serial port found")
#TODO if multiple ports idk, shouldn't ever happen but still
(serport, serdesc, serhwid) = portList[0]
#TODO if port provided from conf, set, otherwise autodetect magical thing just works
aser: aioserial.AioSerial = aioserial.AioSerial(
port=serport,
@ -34,6 +34,7 @@ aser: aioserial.AioSerial = aioserial.AioSerial(
stopbits=serial.STOPBITS_ONE
)
#TODO get this from file da ni hardcoded?
# altho itak je ta script za tist specific tse box in so vsi isti
mapping_toggles = {
@ -59,38 +60,47 @@ shades_mapping = {
}
reverse_lookup = {
1: "master",
2: "audio",
3: "projectors",
1: ("power", "master", ""),
2: ("power", "audio", ""),
3: ("power", "projectors", ""),
5: "main_down",
6: "main_up",
5: ("platno", "main", "MOVING_DOWN"),
6: ("platno", "main", "MOVING_UP"),
7: "side_down",
8: "side_up",
7: ("platno", "side", "MOVING_DOWN"),
8: ("platno", "side", "MOVING_UP"),
9: "shades_down",
10: "shades_up"
9: ("shades", "MOVING_DOWN"),
10: ("shades", "MOVING_UP")
}
#TODO finish this
#TODO add doc comment to every task funciton
async def task_status2mqtt(statusClient: aiomqtt.Client):
while True:
data = await aser.read_until_async()
data = data.decode(errors='ignore').strip()
print("TSE box sent: " + data)
relState = resp_to_relay_state(data)
if relState.relay_id == None:
continue # TODO handling
command = reverse_lookup[relState.relay_id]
action = relState.state
if relState.relay_id is None:
continue # TODO handling - nebi smelo do tega prit anyway
publishTopic = f"{room}/"
publishPayload = "ON" if relState.state else "OFF"
publishPayload = ""
lookup = reverse_lookup[relState.relay_id]
if lookup[0] == "power":
publishTopic += f"{lookup[0]}/{lookup[1]}/status"
publishPayload = '1' if relState.state else '0'
elif lookup[0] == "shades":
publishTopic += f"{lookup[0]}/status"
publishPayload = 'STOPPED' if not relState.state else lookup[1]
elif lookup[0] == "platno":
publishTopic += f"projectors/{lookup[1]}/{lookup[0]}/status"
publishPayload = 'UNKNOWN' if not relState.state else lookup[2]
#publishTopic = f"{room}/projectors/{}"
#publishPayload = "1" if relState.state else "0"
print("Publishing [" + publishPayload + "] to topic [" + publishTopic + "]")
await statusClient.publish(publishTopic, payload=publishPayload)
await asyncio.sleep(10)
await asyncio.sleep(0.2)
async def executeAndPublish(mqttClient, pubTopic, pubPayload, relStat):
@ -99,9 +109,9 @@ async def executeAndPublish(mqttClient, pubTopic, pubPayload, relStat):
print("Sending to TSE box: " + setRelayCmd)
print(f"Also publishing topic [{pubTopic}] with status [{pubPayload}]")
print()
#await aser.write_async(bytes(setRelayCmd + '\r\n', "ascii"))
await aser.write_async(bytes(setRelayCmd + '\r\n', "ascii"))
await mqttClient.publish(pubTopic, payload=pubPayload)
await asyncio.sleep(1)
await asyncio.sleep(0.1) #TODO probably remove
async def handleTsePower(client, sysSelect, cmd):
@ -126,10 +136,10 @@ platnoBckgdMoving = False # mucho importante variable prav zares dedoles
async def platnoTimeout(mqttClient, pubTopic, pubPayload, relStat: RelayState, intent):
global platnoBckgdMoving
await asyncio.sleep(3) #TODO time actual delay
await asyncio.sleep(25) #TODO time actual delay
relStat.state = False
await executeAndPublish(mqttClient, pubTopic, intent, relStat)
platnoBckgdMoving = False
platnoBckgdMoving = False #TODO properly document why this is here and what it does
async def handleTsePlatno(client, proj, cmdType, cmd):
global platnoBckgdMoving
@ -137,7 +147,7 @@ async def handleTsePlatno(client, proj, cmdType, cmd):
# {room} {projectors} {[select]} {platno} {move/goto}
#projector = topicSplit[2]
#command = topicSplit[4]
pubTop = f'{room}/projectors/{proj}/status'
pubTop = f'{room}/projectors/{proj}/platno/status'
if platnoBckgdMoving:
if cmd == 'STOP':
@ -148,7 +158,7 @@ async def handleTsePlatno(client, proj, cmdType, cmd):
await executeAndPublish(client,pubTop, pubPld, rel2)
platnoBckgdMoving = False
else:
return # ignore any other move commands while moving
return #TODO print ignore any other move commands while moving
#movement cmds
elif cmdType == 'move':
@ -159,10 +169,11 @@ async def handleTsePlatno(client, proj, cmdType, cmd):
rel = RelayState(platno_mapping[proj]['DOWN'], True)
else:
return # in case of invalid input skip
platnoBckgdMoving = True
platnoBckgdMoving = True #TODO rename to moving, add comment how it works
pubPld = 'MOVING'
await executeAndPublish(client, pubTop, pubPld, rel)
#TODO WTF HAPPENS IF YOU SEND UP AND DOWN AT ONCE?? (screenshot?)
#TODO daj ignore print ko je locked up
elif cmdType == 'goto':
# print('received GOTO')
rel: RelayState
@ -197,10 +208,10 @@ async def task_command2serial(controlClient: aiomqtt.Client):
cmnd = mesg.payload.decode()
#print('Received on: ', topicVal, ' with:', cmnd)
#print('bfr')
if mesg.topic.matches(f'{room}/projectors/+/platno/+'):
if mesg.topic.matches(f'{room}/projectors/+/platno/#'):
proj = msgTopic[2] # glavni / stranski
cmdType = msgTopic[4] # move / goto
await handleTsePlatno(controlClient, proj, cmdType, cmnd)
await handleTsePlatno(controlClient, proj, cmdType, cmnd) #TODO odzadi index
elif mesg.topic.matches(f'{room}/power/+/set'):
systype = msgTopic[2]
@ -213,14 +224,14 @@ async def task_command2serial(controlClient: aiomqtt.Client):
continue
# code after if block doesnt execute in this case
#print("after")
await asyncio.sleep(0.01)
await asyncio.sleep(0.01) #TODO do we need this? (probably)
async def main():
global room
conf = toml.load('./malinaConfig.toml')
room = conf['global']['room']
async with aiomqtt.Client('localhost', 1883) as client:
async with aiomqtt.Client('localhost', 1883) as client: #TODO omehčaj kodiranje
task_status = asyncio.create_task(task_status2mqtt(client))
task_control = asyncio.create_task(task_command2serial(client))
await asyncio.gather(task_status, task_control)