# coding: utf-8
# python 2 only

# Copyright (c) 2026 TormachTips.com. All rights reserved.
# Licensed under the TormachTips Personal Use License.
# Permission is granted only for private personal use and private personal modification.
# No sharing, publication, distribution, resale, sublicensing, screenshots, code excerpts,
# benchmarks, or videos are permitted without prior written permission.
# Requests:         tormach.1100m@gmail.com
# Information page: https://tormachtips.com/plugins.htm

##############################################
##                                          ##
##   Jog Beeper for ShuttleExpress v0.95    ##
##           www.tormachtips.com            ##
##                                          ##
##############################################

# 0.95 - public beta - 4/2/26

# ShuttleXpress Axis Button Beep Plugin 0.95
# Plays a short WAV ONLY on press of the four axis select buttons (X/Y/Z/A)
# Uses HAL pin polling - no device permissions needed
# Python 2 compatible for PathPilot

import os
import hal  
import glib
import time
import threading
import constants
import subprocess
from ui_hooks import plugin

CURRENT_VER      = "0.95"
SCRIPT_NAME      = "Jog Beeper for ShuttleExpress"
DESCRIPTION      = "An audible beep whenever you press an axis button on the ShuttleExpress."
ENABLED          = 1
DEV_MACHINE      = 1
DEV_MACHINE_FLAG = "/home/operator/gcode/python/dev_machine.txt"
WAV_FILE         = '/home/operator/gcode/images/beep.wav'  
PLAY_CMD         = ['aplay', '-q', WAV_FILE]
COMPONENT        = 'shuttlexpress4.0'  
AXIS_BUTTONS     = ['button-0', 'button-1', 'button-2', 'button-3']  

class UserPlugin(plugin):
    def __init__(self):
        plugin.__init__(self, 'ShuttleXpress Beep')
        dev_machine_found = os.path.exists(DEV_MACHINE_FLAG)
        if dev_machine_found:
            plugin_enabled = DEV_MACHINE
        else:
            plugin_enabled = ENABLED
        if plugin_enabled:
            self.prev_states = {}
            for btn in AXIS_BUTTONS:
                self.prev_states[btn] = False
            glib.timeout_add(5000, self.start_watcher)
            return
        else:
            if dev_machine_found:
                self.error_handler.write("[ShuttleXpress Beep] Dev machine found. Plugin loaded, but disabled by DEV_MACHINE.", constants.ALARM_LEVEL_QUIET)
            else:
                self.error_handler.write("[ShuttleXpress Beep] Plugin loaded, but disabled.", constants.ALARM_LEVEL_QUIET)
                self.error_handler.write("[ShuttleXpress Beep] To enable, open script, find ENABLED = 0 and change to ENABLED = 1", constants.ALARM_LEVEL_QUIET)
            return

    def start_watcher(self):
        try:
            hal.get_value(COMPONENT + '.' + AXIS_BUTTONS[0])
            self.error_handler.write("[Shuttle Beep] Connected to HAL pins - watching for axis button presses",constants.ALARM_LEVEL_QUIET)
            t = threading.Thread(target=self._poll_loop)
            t.daemon = True
            t.start()
            self._play()
        except hal.error as e:
            self.error_handler.write("[Shuttle Beep] HAL connection failed: {}. Check if shuttlexpress4.0 is loaded.".format(e),constants.ALARM_LEVEL_MEDIUM)
        return False

    def _poll_loop(self):
        while True:
            try:
                for btn in AXIS_BUTTONS:
                    pin_name = COMPONENT + '.' + btn
                    current = hal.get_value(pin_name)
                    if current and not self.prev_states[btn]:
                        t = threading.Thread(target=self._play)
                        t.daemon = True
                        t.start()
                    self.prev_states[btn] = current
            except Exception as e:
                self.error_handler.write("[Shuttle Beep] Poll error: {}".format(e),constants.ALARM_LEVEL_MEDIUM)
                time.sleep(5)  
            time.sleep(0.05)  

    def _play(self):
        try:
            subprocess.Popen(PLAY_CMD)  
        except Exception as e:
            self.error_handler.write("[Shuttle Beep] Playback failed: {}".format(e),constants.ALARM_LEVEL_LOW)

DESCRIPTION_LONG = """    If you use the ShuttleExpress Jog Shuttle, this plugin will provide an 
    audible sanity check beep that you've pressed one of the four axis buttons 
    (X Y Z A) and that PathPilot has registered that. </font></p>
    <p><font face="Verdana" size="2">It's good for not slamming your end mills 
    into your work, vise or bed because you meant to move in X and instead it 
    moved in Z, etc. </font></p>
        <p><font face="Verdana" size="2"><a href="plugins/output.htm">Plugin is 
        available on this regularly-updated page.</a></font><p>
    <font face="Verdana" size="2">Also needed:</font><p>
    <b><font face="Verdana" size="2">
    <a href="plugins/beep.wav">beep.wav</a></font></b><font face="Verdana" size="2"><b>
    </b>(place this in /home/operator/gcode/images or edit the script to your 
    custom location)</font>"""