diff --git a/defaults/main.yaml b/defaults/main.yaml index 6d1c595..d8dae47 100644 --- a/defaults/main.yaml +++ b/defaults/main.yaml @@ -36,6 +36,8 @@ sd_unmounted: true arm_arch: false +refresh_special: true + streamer_packages: - ffmpeg - alsa-utils diff --git a/files/service_control_api/website/index.php b/files/service_control_api/website/index.php index 06546aa..cd623ac 100644 --- a/files/service_control_api/website/index.php +++ b/files/service_control_api/website/index.php @@ -9,21 +9,54 @@ $button_recent = false; $button_action = ""; $button_result = ""; $http_host = $_SERVER['HTTP_HOST']; -$debug_string = ""; +$capture_duration = "3"; +$elapsed_time = "0"; -if (isset($_GET['action'])) { - $debug_string = $debug_string."GET called, ".$_GET['action']."
"; - $button_recent = true; - $button_result = runAPI($_GET['action']); - $debug_string = $debug_string."Button Result: ".$button_result."
"; - sleep(1); +// Service Status API Checker +$status_API_URL = "http://172.17.0.1:5000/status"; + +// Use file_get_contents to fetch data from the API +try { + $status_API_response = file_get_contents($status_API_URL); +} catch (Exception $e) { + $status_API_response = '{ "Message": "unknowable", "Status": "unknowable" }'; +} +// Check if the request was successful +if ($status_API_response === FALSE) { + $data = "Failed to fetch data."; } -function runAPI($submitted_status) { - if(!isset($debug_string)){ - $debug_string = ""; +else { + // Decode the JSON response (assuming the API returns JSON) + $data = json_decode($status_API_response, true); + if (isset($data['Message'])) { + $message = $data['Message']; + } else { + $message = "No message found in the response."; } - $debug_string = $debug_string."runAPI called, ".$submitted_status."
"; + if (isset($data['Status'])) { + $status = $data['Status']; + } else { + $status = "None"; + } + if (isset($data['Elapsed_Time'])) { + $elapsed_time = $data['Elapsed_Time']; + } else { + $elapsed_time = "-1"; + } +} + +if (isset($_GET['new_duration'])){ + $button_recent = true; + set_duration($_GET['new_duration']); +} + +if (isset($_GET['action'])) { + $button_recent = true; + $button_result = service_manager($_GET['action']); +} + +function service_manager($submitted_status) { switch ($submitted_status) { case "stop": $apiUrl = "http://172.17.0.1:5000/stop"; @@ -35,8 +68,6 @@ function runAPI($submitted_status) { $apiUrl = "http://172.17.0.1:5000/status"; break; } - // API URL - $debug_string = $debug_string."After switch, apiUrl is ".$apiUrl."
"; // Use file_get_contents or cURL to fetch the API data try { $response = file_get_contents($apiUrl); @@ -44,77 +75,15 @@ function runAPI($submitted_status) { $response = '{ "Message": "unknowable", "Status": "unknowable" }'; } if ($response === FALSE) { - $debug_string = $debug_string."Response ERROR!!
"; return "error"; // API error } // Decode the JSON response (assuming the API returns JSON) $data = json_decode($response, true); - $debug_string = $debug_string."Data from API call: ".$data['Message']."
"; // Assuming the API returns a single word result (like "success", "failure", etc.) return isset($data['Status']) ? $data['Status'] : 'unknown'; } -// | awk '{printf(\"%.5f\n\", $1)}' -// | awk '{printf(\"%.5f\n\", $1)}' - - -function getGPS(){ - // check the API - $gps_data = file_get_contents("http://172.17.0.1:5000/return_gps"); - try { - $gps_data = json_decode($gps_data, true); - - } catch (Exception $e){ - $gps_data = '{c}'; - } - - //set the vars - $LAT = $gps_data['lat']; - $LON = $gps_data['lon']; - $SPEED = $gps_data['speed']; - - if (is_null($LAT) || $LAT == 0) { - return "No GPS data available - null LAT"; - } - if (is_null($LON) || $LON == 0) { - return "No GPS data available - null LON"; - } - - return $LAT.", ".$LON.", ".$SPEED."mph"; -} - -// URL of the external API -$apiUrl = "http://172.17.0.1:5000/status"; - -// Use file_get_contents to fetch data from the API -try { - $response = file_get_contents($apiUrl); -} catch (Exception $e) { - $response = '{ "Message": "unknowable", "Status": "unknowable" }'; -} - -// Check if the request was successful -if ($response === FALSE) { - $data = "Failed to fetch data."; -} -else { - // Decode the JSON response (assuming the API returns JSON) - $data = json_decode($response, true); - // If you want to display specific data, adjust this part - // For example, if the API returns a 'message' key, display it - if (isset($data['Message'])) { - $message = $data['Message']; - } else { - $message = "No message found in the response."; - } - if (isset($data['Status'])) { - $status = $data['Status']; - } else { - $status = "None"; - } -} - switch ($status) { case "active": $button_text = "Stop Service"; @@ -168,6 +137,133 @@ if($button_recent){ exit(); // Always include exit() after headers are sent } + +function duration_button_handler($button_ID, $function) { + // Duration Status API Checker + $duration_API_URL = "http://172.17.0.1:5000/check_duration"; + + // Use file_get_contents to fetch data from the API + try { + $duration_API_URL = file_get_contents($duration_API_URL); + } catch (Exception $e) { + $duration_API_URL = '{ "Message": "unknowable", "Status": "unknowable" }'; + } + // Check if the request was successful + if ($duration_API_URL === FALSE) { + $raw_duration = "Failed to fetch data."; + } + + else { + // Decode the JSON response (assuming the API returns JSON) + $raw_duration = json_decode($duration_API_URL, true); + if (isset($raw_duration['duration'])) { + $capture_duration = $raw_duration['duration']; + } else { + $capture_duration = "3"; + } + } + + + // Service Status API Checker + $status_API_URL = "http://172.17.0.1:5000/status"; + + // Use file_get_contents to fetch data from the API + try { + $status_API_response = file_get_contents($status_API_URL); + } catch (Exception $e) { + $status_API_response = '{ "Message": "unknowable", "Status": "unknowable" }'; + } + // Check if the request was successful + if ($status_API_response === FALSE) { + $data = "Failed to fetch data."; + } + + else { + // Decode the JSON response (assuming the API returns JSON) + $data = json_decode($status_API_response, true); + if (isset($data['Message'])) { + $message = $data['Message']; + } else { + $message = "No message found in the response."; + } + if (isset($data['Status'])) { + $status = $data['Status']; + } else { + $status = "None"; + } + } + + # function 0 - return class string + # function 1 - return active string + switch ($function) { + case "0": + # these classes are weird because reasons + # specifically because the classes are named + # based on service status + # to decode this, inactive is green + # and deactivating is blue + # so all the selectable buttons are blue and the active one is green + if($button_ID == $capture_duration){ + return "inactive"; + } + else { + return "selected"; + } + break; + + case "1": + # this disables clicking the active button + if($status == "active") { + return " disabled"; + } + else if($button_ID == $capture_duration){ + return " disabled"; + } + else { + return ""; + } + break; + + default: + break; + } + +} + +# this will be an integer from 0-3 for +# 30min, 1hr, 2hr, and 6rh respectively +# info = { +# "duration": new_duration +# } +function set_duration($duration) { + switch ($duration) { + case "0": + $apiUrl = "http://172.17.0.1:5000/store_duration?new_duration=0"; + break; + case "1": + $apiUrl = "http://172.17.0.1:5000/store_duration?new_duration=1"; + break; + case "2": + $apiUrl = "http://172.17.0.1:5000/store_duration?new_duration=2"; + break; + case "3": + $apiUrl = "http://172.17.0.1:5000/store_duration?new_duration=3"; + break; + default: + $apiUrl = "http://172.17.0.1:5000/status"; + break; + } + try { + $response = file_get_contents($apiUrl); + } catch (Exception $e) { + $response = '{ "Message": "unknowable", "Status": "unknowable" }'; + } + if ($response === FALSE) { + return "error"; // API error + } +} + + ?> @@ -185,22 +281,53 @@ if($button_recent){
-

+

+ +

+ + + + + + + + + + +
+ + + +
+ + + +
+ +
+

+

".htmlspecialchars($message)."

"; + if ($status == "active"){ + echo "Time Elapsed:
".htmlspecialchars($elapsed_time)."s

"; + } echo "Current Date:
".date("F j, Y, g:i:s a")."

"; - echo "Current GPS Data:
".getGPS(); ?>

- +

+

+ - + + diff --git a/files/service_control_api/website/styles.css b/files/service_control_api/website/styles.css index 066c1b6..cb36658 100644 --- a/files/service_control_api/website/styles.css +++ b/files/service_control_api/website/styles.css @@ -69,7 +69,7 @@ button:hover { background: radial-gradient(circle, #671281 0%, #8423a1 100%); color: #bdc3c7; /* Dimmer text color */ } -.deactivating { +.selected { background-color: #003699; background: radial-gradient(circle, #003699 0%, #337aff 100%); color: #bdc3c7; /* Dimmer text color */ diff --git a/tasks/main.yaml b/tasks/main.yaml index f0d8e6a..ca91562 100644 --- a/tasks/main.yaml +++ b/tasks/main.yaml @@ -15,28 +15,28 @@ set_fact: cpu_architecture: "{{ cpu_architecture_output.stdout_lines[0] }}" -- name: Video Capture - Install Packages - when: not refresh_special | bool - apt: - name: - - "{{ streamer_packages_items }}" - state: present - loop: "{{ streamer_packages }}" - loop_control: - loop_var: streamer_packages_items +#- name: Video Capture - Install Packages +# when: not refresh_special | bool +# apt: +# name: +# - "{{ streamer_packages_items }}" +# state: present +# loop: "{{ streamer_packages }}" +# loop_control: +# loop_var: streamer_packages_items +# +#- name: Video Capture - SD Card Handler +# when: mount_sd | bool +# include_tasks: sd_handler.yaml +# +#- name: Video Capture - Configure MediaMTX +# include_tasks: mediamtx.yaml +# +#- name: Video Capture - Configure Streaming +# include_tasks: streamer.yaml -- name: Video Capture - SD Card Handler - when: mount_sd | bool - include_tasks: sd_handler.yaml - -- name: Video Capture - Configure MediaMTX - include_tasks: mediamtx.yaml - -- name: Video Capture - Configure Streaming - include_tasks: streamer.yaml - -#- name: Video Capture - Configure service control -# include_tasks: service_control.yaml +- name: Video Capture - Configure service control + include_tasks: service_control.yaml ... \ No newline at end of file diff --git a/tasks/service_control.yaml b/tasks/service_control.yaml index 6810175..3afcaa9 100644 --- a/tasks/service_control.yaml +++ b/tasks/service_control.yaml @@ -60,6 +60,21 @@ dest: /etc/systemd/system/service_control.service mode: 0644 + - name: video_capture - service timeout helper files + block: + + - name: video_capture - create service_timeout.sh + template: + src: service_timeout.sh.j2 + dest: "{{ service_control_folder }}/service_timeout.sh" + mode: 0755 + + - name: video_capture - create service_timeout.service + template: + src: service_timeout.service.j2 + dest: /etc/systemd/system/service_timeout.service + mode: 0644 + # daemon reload - name: video_capture - service_control api - daemon reload systemd: @@ -72,6 +87,11 @@ state: started enabled: yes + - name: video_capture - service_control api - enable and start service timeoue api + systemd: + name: service_timeout.service + state: started + enabled: yes ############################################### @@ -102,24 +122,27 @@ owner: root group: root -# - name: service_control_website - template index.php -# template: -# src: index-service_control.php.j2 -# dest: "{{ service_control_web_folder }}/html/index.php" -# mode: 0644 + #- name: service_control_website - template index.php + # template: + # src: index-service_control.php.j2 + # dest: "{{ service_control_web_folder }}/html/index.php" + # mode: 0644 ############################################### # Start service_control_website ############################################### -# https://unix.stackexchange.com/questions/265704/start-stop-a-systemd-service-at-specific-times -# i can create several conflicting services with various timeouts + # https://unix.stackexchange.com/questions/265704/start-stop-a-systemd-service-at-specific-times + # i can create several conflicting services with various timeouts - name: start service_control_website + when: not refresh_special | bool block: + - name: set container variables set_fact: container_name: "service_control_website" container_http_port: "8081" + extra_volumes: "" - name: service_control_website - template config template: diff --git a/tasks/streamer.yaml b/tasks/streamer.yaml index 3056db3..40af37e 100644 --- a/tasks/streamer.yaml +++ b/tasks/streamer.yaml @@ -37,7 +37,7 @@ # same with video, the lsusb ID is 534d:0021 - name: video_capture - get video device - shell: "v4l2-ctl --list-devices -z {{ lsusb_device_ID }}| grep video | head -n 1" + shell: "v4l2-ctl --list-devices -z {{ lsusb_device_ID }} | grep video | head -n 1 | awk '{print $1}'" register: video_ID_0 - name: video_capture - set video_device diff --git a/templates/app-service.py.j2 b/templates/app-service.py.j2 index 416adb7..3536d50 100644 --- a/templates/app-service.py.j2 +++ b/templates/app-service.py.j2 @@ -4,6 +4,7 @@ from lxml import html from flask import Flask, request, jsonify import json import os +from datetime import datetime, timedelta app = Flask(__name__) @@ -49,10 +50,81 @@ def service_status(): result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) command = "systemctl status {{ service_control_name }} | grep Active | cut -d ':' -f 2 | cut -d ' ' -f 2" status = subprocess.run(command, shell=True, check=True, capture_output=True, text=True) - return {"Message": result.stdout.strip('\n'), "Status": status.stdout.strip('\n')} + if status.stdout.strip('\n') == "active": + elapsed_time = check_time_elapsed(result.stdout.strip('\n')) + times_up(elapsed_time) + else: + elapsed_time = -1 + return {"Elapsed_Time": elapsed_time, "Service Name": "{{ service_control_name }}", "Message": result.stdout.strip('\n'), "Status": status.stdout.strip('\n')} except subprocess.CalledProcessError as e: return {"Error": e.strip('\n')} +def save_duration(new_duration): + # this will be an integer from 0-3 for + # 30min, 1hr, 2hr, and 6rh respectively + seconds = 1800 + if new_duration == "0": + seconds = 1800 + if new_duration == "1": + seconds = 3600 + if new_duration == "2": + seconds = 7200 + if new_duration == "3": + seconds = 21600 + + info = { + "duration": new_duration, + "seconds": seconds + } + with open("duration.json", "w") as file: + json.dump(info, file, indent=4) + return {"status": "duration.json stored"} + +def get_duration(): + try: + with open('duration.json', 'r') as file: + data = json.load(file) + return (data) + except Exception as e: + return {"error": str(e)}, 500 + +def check_time_elapsed(time_str): + # Extract the time part from the string + datetime_extract = time_str.split("since ")[1].split(";")[0] + + try: + time_format = "%a %Y-%m-%d %H:%M:%S %Z" + given_time = datetime.strptime(datetime_extract, time_format) + except ValueError as e: + raise ValueError(f"Error parsing the time string: {datetime_extract}" + str(e)) + + # Get the current time + now = datetime.now() + + # Calculate the difference in seconds + delta = now - given_time + total_seconds = int(delta.total_seconds()) + + return total_seconds + +def times_up(time_elapsed): + duration_json = get_duration() + stored_duration = duration_json["duration"] + if stored_duration == 0: + if time_elapsed > 1800: + stop_service() + elif stored_duration == 1: + if time_elapsed > 3600: + stop_service() + elif stored_duration == 2: + if time_elapsed > 7200: + stop_service() + elif stored_duration == 3: + if time_elapsed > 21600: + stop_service() + + + @app.route('/start', methods=['GET']) def start(): try: @@ -77,6 +149,27 @@ def status(): print(e) return jsonify({'error': e}), 400 +@app.route('/check_duration', methods=['GET']) +def check_duration(): + try: + return jsonify(get_duration()) + except ValueError as e: + print(e) + return jsonify({'error': e}), 400 + +@app.route('/store_duration', methods=['GET']) +def store_duration(): + try: + new_duration = request.args.get('new_duration') + except ValueError as e: + return jsonify({'error': e}), 400 + if new_duration: + try: + return jsonify(save_duration(new_duration)) + except ValueError as e: + print(e) + return jsonify({'error': e}), 400 + @app.route('/test', methods=['GET']) def test(): return jsonify({'message': 'Hello there'}) diff --git a/templates/service_timeout.service.j2 b/templates/service_timeout.service.j2 new file mode 100644 index 0000000..25b500d --- /dev/null +++ b/templates/service_timeout.service.j2 @@ -0,0 +1,15 @@ + +[Unit] +Description=VCR Streaming Service Timeout Helper +After=network.target + +[Service] +Type=simple +WorkingDirectory={{ service_control_folder }} +ExecStart=/bin/bash {{ service_control_folder }}/service_timeout.sh +Restart=always +User=root +Group=root + +[Install] +WantedBy=multi-user.target diff --git a/templates/service_timeout.sh.j2 b/templates/service_timeout.sh.j2 new file mode 100644 index 0000000..26fb4e4 --- /dev/null +++ b/templates/service_timeout.sh.j2 @@ -0,0 +1,17 @@ +#!/bin/bash + +i=1 +while [ $i ] +do + +TIME_ELAPSED=$(curl -s http://172.17.0.1:5000/status | jq .Elapsed_Time) +TIMEOUT_VALUE=$(cat {{ streaming_working_folder }}/service_control/duration.json | jq .seconds) +if [[ $TIME_ELAPSED -gt $TIMEOUT_VALUE ]]; then + curl -s http://172.17.0.1:5000/stop + i=0 +fi + +sleep 1 + +done +