async def _get_audio_mono(hass, call): import subprocess try: if ais_global.has_root(): mode = subprocess.check_output( 'su -c "settings get system master_mono"', shell=True, # nosec timeout=10, ) mode = mode.decode("utf-8").replace("\n", "") else: mode = "0" if mode == "1": await hass.services.async_call( "input_boolean", "turn_on", {"entity_id": "input_boolean.ais_audio_mono"}, ) else: await hass.services.async_call( "input_boolean", "turn_off", {"entity_id": "input_boolean.ais_audio_mono"}, ) except Exception as e: _LOGGER.info("Can't get audio master_mono from system settings! " + str(e))
async def _set_clock_display_text(hass, call): if not ais_global.has_root(): return text = call.data["text"] comm = r'su -c "echo ' + text + ' > /sys/class/fd655/panel"' await _run(comm)
async def _screen_stream_command(hass, call): if not ais_global.has_root(): return name = call.data["name"] sX = call.data["sX"] sY = call.data["sY"] eX = 0 eY = 0 if "eX" in call.data: eX = call.data["eX"] if "eY" in call.data: eY = call.data["eY"] comm = r"" if name == "pan": comm = ("http://127.0.0.1:9966/ais-pan?sX=" + str(sX) + "&sY=" + str(sY) + "&eX=" + str(eX) + "&eY=" + str(eY)) elif name == "tap": comm = "http://127.0.0.1:9966/ais-click?x=" + str(sX) + "&y=" + str(sY) elif name == "back": comm = "http://127.0.0.1:9966/ais-back" web_session = aiohttp_client.async_get_clientsession(hass) try: async with async_timeout.timeout(1): await web_session.get(comm) except asyncio.TimeoutError: _LOGGER.debug("Timeout during screen stream command")
def rclone_remove_drive(self, name): remotes = rclone_get_remotes_long() drive_exist = False for r in remotes: if name == r["name"]: drive_exist = True if drive_exist: # Delete an existing remote fix_rclone_config_permissions() rclone_cmd_remove_drive = ("rclone config delete " + name + " " + G_RCLONE_CONF) os.system(rclone_cmd_remove_drive) else: _LOGGER.error("rclone_remove_drive: NO drive in Rclone, name: " + name) # fusermount if not ais_global.has_root(): os.system( "fusermount -u /data/data/pl.sviete.dom/dom_cloud_drives/" + name) else: os.system( 'su -mm -c "export PATH=$PATH:/data/data/pl.sviete.dom/files/usr/bin/; ' + ' fusermount -u /data/data/pl.sviete.dom/dom_cloud_drives/"' + name) # delete drive folder os.system("rm -rf /data/data/pl.sviete.dom/dom_cloud_drives/" + name)
async def _change_wm_overscan(hass, call): if "value" not in call.data: return if not ais_global.has_root(): return new_value = call.data["value"] cl = 0 ct = 0 cr = 0 cb = 0 try: import subprocess overscan = "" overscan = subprocess.check_output( "su -c \"dumpsys display | grep -o 'overscan.*' | cut -d')' -f1 | rev | cut -d'(' -f1 | rev\"", shell=True, # nosec timeout=10, ) overscan = overscan.decode("utf-8").replace("\n", "") if "," in overscan: cl = int(overscan.split(",")[0]) ct = int(overscan.split(",")[1]) cr = int(overscan.split(",")[2]) cb = int(overscan.split(",")[3]) except Exception: _LOGGER.warning(f"Can't get current overscan {overscan}") # [reset|LEFT,TOP,RIGHT,BOTTOM] if new_value == "reset": comm = r'su -c "wm overscan reset"' elif new_value == "left": comm = (r'su -c "wm overscan ' + str(int(cl) - 3) + "," + str(ct) + "," + str(cr) + "," + str(cb) + '"') elif new_value == "top": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(int(ct) - 3) + "," + str(cr) + "," + str(cb) + '"') elif new_value == "right": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(ct) + "," + str(int(cr) - 3) + "," + str(cb) + '"') elif new_value == "bottom": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(ct) + "," + str(cr) + "," + str(int(cb) - 3) + '"') elif new_value == "-left": comm = (r'su -c "wm overscan ' + str(int(cl) + 3) + "," + str(ct) + "," + str(cr) + "," + str(cb) + '"') elif new_value == "-top": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(int(ct) + 3) + "," + str(cr) + "," + str(cb) + '"') elif new_value == "-right": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(ct) + "," + str(int(cr) + 3) + "," + str(cb) + '"') elif new_value == "-bottom": comm = (r'su -c "wm overscan ' + str(cl) + "," + str(ct) + "," + str(cr) + "," + str(int(cb) + 3) + '"') else: _LOGGER.error(f"Value for overscan provided {new_value}") return await _run(comm)
def grant_write_to_sdcard(): if not ais_global.has_root(): return try: ret_output = subprocess.check_output( 'su -c "pm grant launcher.sviete.pl.domlauncherapp android.permission.READ_EXTERNAL_STORAGE"', shell=True, # nosec timeout=15, ) _LOGGER.info(str(ret_output.decode("utf-8"))) ret_output = subprocess.check_output( 'su -c "pm grant launcher.sviete.pl.domlauncherapp android.permission.WRITE_EXTERNAL_STORAGE"', shell=True, # nosec timeout=15, ) _LOGGER.info(str(ret_output.decode("utf-8"))) ret_output = subprocess.check_output( 'su -c "pm grant pl.sviete.dom android.permission.READ_EXTERNAL_STORAGE"', shell=True, # nosec timeout=15, ) _LOGGER.info(str(ret_output.decode("utf-8"))) ret_output = subprocess.check_output( 'su -c "pm grant pl.sviete.dom android.permission.WRITE_EXTERNAL_STORAGE"', shell=True, # nosec timeout=15, ) _LOGGER.info(str(ret_output.decode("utf-8"))) except Exception as e: _LOGGER.error(str(e))
def rclone_mount_drive(self, name): remotes = rclone_get_remotes_long() # get uid and gid uid = str(os.getuid()) gid = str(os.getgid()) drive_exist = False for r in remotes: if name == r["name"]: drive_exist = True if drive_exist: if not ais_global.has_root(): # to suport local test rclone_cmd_mount = ( "rclone mount " + name + ":/ /data/data/pl.sviete.dom/dom_cloud_drives/" + name + " --uid " + uid + " --gid " + gid + " --allow-non-empty " + " " + G_RCLONE_CONF) else: # fix_rclone_config_permissions() # prepare mount command rclone_cmd_mount = ( 'su -mm -c "export PATH=$PATH:/data/data/pl.sviete.dom/files/usr/bin/; rclone mount ' + name + ":/ /data/data/pl.sviete.dom/dom_cloud_drives/" + name + " --allow-other" + " --uid " + uid + " --gid " + gid + " " + G_RCLONE_CONF + '"') os.system("mkdir -p /data/data/pl.sviete.dom/dom_cloud_drives/" + name) os.system(rclone_cmd_mount) else: self.say("Nie masz dodanego dysku zdalnego o nazwie " + name)
async def _set_scaling_governor(hass, call): if not ais_global.has_root() or multiprocessing.cpu_count() > 5: return # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors scaling_available_governors = ["hotplug", "interactive", "performance"] # interactive is default scaling scaling = "interactive" if "scaling" in call.data: scaling = call.data["scaling"] # default powersave freq # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies # scaling_available_frequencies = 100000 250000 500000 667000 1000000 1200000 freq = "1000000" if scaling == "performance": freq = "1200000" if scaling in scaling_available_governors: comm = (r'su -c "echo ' + scaling + ' > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"') await _run(comm) comm = (r'su -c "echo ' + freq + ' > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"') await _run(comm)
async def _change_sound_mode(hass, call): # set the mode if "mode" not in call.data: _LOGGER.error("No mode in call") return if not ais_global.has_root(): return mode = call.data["mode"] if mode not in ( "NORMAL", "BOOST", "TREBLE", "POP", "ROCK", "CLASSIC", "JAZZ", "DANCE", "R&P", ): _LOGGER.error("Unrecognized mode in call: " + mode) return comm = ( r'su -c "stty -F /dev/ttyS0 9600 && echo COM+SETEQ{}\r\n > /dev/ttyS0"' .format(mode)) os.system(comm)
async def _change_work_mode(hass, call): # set the mode if "mode" not in call.data: _LOGGER.error("No mode in call") return if not ais_global.has_root(): return from threading import Timer mode = call.data["mode"] if mode not in ("BT", "AX"): _LOGGER.error("Unrecognized mode in call: " + mode) return if mode == "BT": await hass.services.async_call("ais_ai_service", "say_it", {"text": "Głośnik w trybie Bluetooth "}) # change 2 seconds after click t = Timer(2, set_bt_mode) t.start() else: comm = r'su -c "stty -F /dev/ttyS0 9600 && echo COM+MAX\r\n > /dev/ttyS0"' os.system(comm) # say 2 seconds after change import time time.sleep(2) await hass.services.async_call("ais_ai_service", "say_it", {"text": "Głośnik w trybie AUX-IN "})
async def prepare_usb_device(hass, device_info): # start zigbee2mqtt service # add info in app if device_info["id"] == G_ZIGBEE_ID: # Register the built-in zigbee panel # hass.components.frontend.async_register_built_in_panel( # "aiszigbee", # require_admin=True, # sidebar_title="Zigbee", # sidebar_icon="mdi:zigbee", # update=True, # ) # check if zigbee already exists if not os.path.isdir( "/data/data/pl.sviete.dom/files/home/zigbee2mqtt"): await hass.services.async_call( "ais_ai_service", "say_it", { "text": "Nie znaleziono pakietu Zigbee2Mqtt zainstaluj go przed pierwszym uruchomieniem usługi " "Zigbee. Szczegóły w dokumentacji Asystenta domowego." }, ) return # fix permitions uid = str(os.getuid()) gid = str(os.getgid()) if ais_global.has_root(): await _run("su -c 'chown " + uid + ":" + gid + " /dev/ttyACM0'") # TODO check the /dev/ttyACM.. number if ais_global.has_root(): await _run("su -c 'chmod 777 /dev/ttyACM0'") # restart-delay 120000 milisecond == 2 minutes cmd_to_run = ( "pm2 restart zigbee || pm2 start /data/data/pl.sviete.dom/files/home/zigbee2mqtt/index.js " "--name zigbee --output /dev/null --error /dev/null --restart-delay=120000" ) await _run(cmd_to_run) # # if ais_global.G_AIS_START_IS_DONE: await hass.services.async_call("ais_ai_service", "say_it", {"text": "Uruchomiono serwis zigbee"})
async def _key_event(hass, call): if "key_code" not in call.data: return if not ais_global.has_root(): return key_code = call.data["key_code"] await _run("su -c 'input keyevent " + key_code + "'")
async def _change_host_name(hass, call): if "hostname" not in call.data: return if not ais_global.has_root(): return new_host_name = call.data["hostname"] command = 'su -c "setprop net.hostname ' + new_host_name + '"' await _run(command)
async def _cec_command(hass, call): if "command" not in call.data: return if not ais_global.has_root(): return command = call.data["command"] cec_cmd = "su -c 'echo " + command + " > /sys/class/cec/cmd'" await _run(cec_cmd)
def _change_audio_to_mono(hass, call): mode = hass.states.get("input_boolean.ais_audio_mono").state info_text = "" if mode == "on": if ais_global.has_root(): comm = r'su -c "settings put system master_mono 1"' os.system(comm) info_text = "włączony" else: if ais_global.has_root(): comm = r'su -c "settings put system master_mono 0"' os.system(comm) info_text = "wyłączony" if ais_global.G_AIS_START_IS_DONE: yield from hass.services.async_call( "ais_ai_service", "say_it", {"text": "Dźwięk mono " + info_text})
async def _execute_stop(hass, call): import subprocess if not ais_global.has_root(): return subprocess.Popen("su -c 'reboot -p'", shell=True, stdout=None, stderr=None) # nosec
async def _init_local_sdcard(hass, call): if not ais_global.has_root(): return script = str(os.path.dirname(__file__)) script += "/scripts/init_local_sdcard.sh" import subprocess subprocess.Popen(script, shell=True, stdout=None, stderr=None) # nosec
async def _disable_irda_remote(hass, call): if not ais_global.has_root(): return # aml_keypad -> event0 irda remote comm = r'su -c "rm -rf /dev/input/event0"' await _run(comm) # cec_input -> event2 hdmi cec comm = r'su -c "rm -rf /dev/input/event2"' await _run(comm)
async def _led(hass, call): if "brightness" not in call.data: return if not ais_global.has_root(): return brightness = call.data["brightness"] script = str(os.path.dirname(__file__)) script += "/scripts/led.sh" await _run("su -c ' " + script + " " + str(brightness) + "'")
async def _exec_tonos_command(hass, call): if "command" not in call.data: _LOGGER.error("No command in call") return if not ais_global.has_root(): return command = call.data["command"] # execute control instruction on amplifier via UART comm = r'su -c "stty -F /dev/ttyS0 115200 && echo {} > /dev/ttyS0 && printf "\x0d" > /dev/ttyS0 && printf "\x0d" ' \ r'> /dev/ttyS0"'.format(command) os.system(comm)
async def _exec_command(hass, call): if "command" not in call.data: _LOGGER.error("No command in call") return if not ais_global.has_root(): return command = call.data["command"] # execute control instruction on amplifier via UART comm = r'su -c "stty -F /dev/ttyS0 9600 && echo COM+{}\r\n > /dev/ttyS0"'.format( command) os.system(comm)
async def _set_io_scheduler(hass, call): if not ais_global.has_root(): return # /sys/block/mmcblk0/queue/scheduler available_io_schedulers = ["noop", "deadline", "cfq"] # noop is now default scheduler scheduler = "noop" if "scheduler" in call.data: scheduler = call.data["scheduler"] if scheduler in available_io_schedulers: comm = r'su -c "echo ' + scheduler + ' > /sys/block/mmcblk0/queue/scheduler"' await _run(comm)
def fix_rclone_config_permissions(): # fix permissions uid = str(os.getuid()) gid = str(os.getgid()) if ais_global.has_root(): fix_rclone_cmd = ('su -c "chown ' + uid + ":" + gid + " " + G_RCLONE_CONF_FILE + '"') try: subprocess.check_output(fix_rclone_cmd, shell=True) # nosec except Exception as e: _LOGGER.error( "Nie można uzyskać uprwanień do konfiguracji dysków: " + str(e))
async def _key_event(hass, call): if "key_code" not in call.data: return if not ais_global.has_root(): return key_code = call.data["key_code"] import subprocess subprocess.Popen( "su -c 'input keyevent " + key_code + "'", shell=True, # nosec stdout=None, stderr=None, )
async def async_setup(hass, config): """Register the service.""" config = config.get(DOMAIN, {}) async def change_work_mode(service): await _change_work_mode(hass, service) async def change_sound_mode(service): await _change_sound_mode(hass, service) async def exec_command(service): await _exec_command(hass, service) async def exec_tonos_command(service): await _exec_tonos_command(hass, service) async def change_audio_to_mono(service): await _change_audio_to_mono(hass, service) async def get_audio_mono(service): await _get_audio_mono(hass, service) async def set_audio_routing(service): await _set_audio_routing(hass, service) # register services hass.services.async_register(DOMAIN, "change_work_mode", change_work_mode) hass.services.async_register(DOMAIN, "change_sound_mode", change_sound_mode) hass.services.async_register(DOMAIN, "exec_command", exec_command) hass.services.async_register(DOMAIN, "change_audio_to_mono", change_audio_to_mono) hass.services.async_register(DOMAIN, "get_audio_mono", get_audio_mono) hass.services.async_register(DOMAIN, "exec_tonos_command", exec_tonos_command) hass.services.async_register(DOMAIN, "set_audio_routing", set_audio_routing) # temporarily suppress all kernel logging to the console if ais_global.has_root(): os.system("su -c 'dmesg -n 1'") # set permissions to /dev/ttyS0 os.system("su -c 'chmod 666 /dev/ttyS0'") # disable tone on start # os.system(r'su -c "stty -F /dev/ttyS0 9600 && echo COM+TONEOFF\r\n > /dev/ttyS0"') # set aux mode on start os.system( r'su -c "stty -F /dev/ttyS0 9600 && echo COM+MAX\r\n > /dev/ttyS0"' ) return True
async def _change_host_name(hass, call): if "hostname" not in call.data: return if not ais_global.has_root(): return new_host_name = call.data["hostname"] file = "/data/data/pl.sviete.dom/.ais/ais-hostname" command = 'echo "net.hostname = ' + new_host_name + '" > ' + file import subprocess process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) # nosec process.wait() command = 'su -c "/data/data/pl.sviete.dom/.ais/run_as_root.sh"' process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) # nosec process.wait()
async def _led(hass, call): if "brightness" not in call.data: return if not ais_global.has_root(): return brightness = call.data["brightness"] script = str(os.path.dirname(__file__)) script += "/scripts/led.sh" import subprocess subprocess.Popen( "su -c ' " + script + " " + str(brightness) + "'", shell=True, # nosec stdout=None, stderr=None, )
def get_current_android_apk_version(): if not ais_global.has_root(): return "0", "0", "0", "0" try: apk_dom_version = subprocess.check_output( 'su -c "dumpsys package pl.sviete.dom | grep versionName"', shell=True, # nosec timeout=15, ) apk_dom_version = (apk_dom_version.decode("utf-8").replace( "\n", "").strip().replace("versionName=", "")) apk_launcher_version = subprocess.check_output( 'su -c "dumpsys package launcher.sviete.pl.domlauncherapp | grep versionName"', shell=True, # nosec timeout=15, ) apk_launcher_version = (apk_launcher_version.decode("utf-8").replace( "\n", "").strip().replace("versionName=", "")) apk_tts_version = subprocess.check_output( 'su -c "dumpsys package com.google.android.tts | grep versionName"', shell=True, # nosec timeout=15, ) apk_tts_version = (apk_tts_version.decode("utf-8").replace( "\n", "").strip().replace("versionName=", "")) apk_stt_version = subprocess.check_output( 'su -c "dumpsys package com.google.android.googlequicksearchbox | grep versionName"', shell=True, # nosec timeout=15, ) apk_stt_version = (apk_stt_version.decode("utf-8").replace( "\n", "").strip().replace("versionName=", "")) return apk_dom_version, apk_launcher_version, apk_tts_version, apk_stt_version except Exception as e: _LOGGER.info("Can't get android apk version! " + str(e)) return "0", "0", "0", "0"
async def _hdmi_control_disable(hass, call): if not ais_global.has_root(): return comm = r'su -c "settings put global hdmi_control_enabled 0"' await _run(comm)
def set_bt_mode(): if not ais_global.has_root(): return comm = r'su -c "stty -F /dev/ttyS0 9600 && echo COM+MBT\r\n > /dev/ttyS0"' os.system(comm)