diff --git a/archive/docker-compose-owncast.yaml.j2 b/archive/docker-compose-owncast.yaml.j2
new file mode 100644
index 0000000..3b64b34
--- /dev/null
+++ b/archive/docker-compose-owncast.yaml.j2
@@ -0,0 +1,12 @@
+services:
+
+ owncast:
+ container_name: owncast
+ image: owncast/owncast:latest
+ volumes:
+ - {{ owncast_working_folder}}:/app/data
+ ports:
+ - {{ owncast_web_port }}:8080
+ - 1935:1935
+ restart: always
+ network_mode: bridge
\ No newline at end of file
diff --git a/files/notes.txt b/archive/notes.txt
similarity index 68%
rename from files/notes.txt
rename to archive/notes.txt
index 080b98e..30987c4 100644
--- a/files/notes.txt
+++ b/archive/notes.txt
@@ -73,3 +73,14 @@ ffmpeg -r 24 -pattern_type glob -i "/var/opt/mattstream/$TODAY/*.jpg" \
# Slap a copy of this somewhere convenient for me to grab it
cp /var/opt/mattstream/$TODAY/$TODAY.mp4 /media/pleiades/matt-lapse/$TODAY.mp4
+| | | | |
+| :---------------------- | :---------------------- | :---------------------- | :---------------------- |
+| **Tuesday:** | **Wednesday:** | **Thursday:** | **Friday:** |
+| • Soda Springs, CA | • Battle Mountain, NV | • Sidney, NE | • Manitowoc, WI |
+| • Fernley, NV | • West Wendover, NV | • North Platte, NE | • KEVIN!!!!!! |
+| | • Park City, UT | • Kearney, NE | |
+| | • Rock Springs, WY | • Lincoln, NE | |
+| | • Rawlins, WY | • Des Moins, IA | |
+| | • Laramie, WY | • Iowa City, IA | |
+| | | • Madison, WI | |
+
diff --git a/archive/owncast.yaml b/archive/owncast.yaml
new file mode 100644
index 0000000..85a9d8a
--- /dev/null
+++ b/archive/owncast.yaml
@@ -0,0 +1,27 @@
+###############################################
+# Start photo_refresh
+###############################################
+- name: start owncast
+ block:
+
+ # Create service Folder
+ - name: carputer - owncast - create owncast_working_folder folder
+ file:
+ path: "{{ owncast_working_folder }}"
+ state: directory
+ mode: '0755'
+ owner: root
+ group: root
+
+ - name: carputer - owncast - template config
+ template:
+ src: docker-compose-owncast.yaml.j2
+ dest: "{{ owncast_working_folder }}/docker-compose.yaml"
+ mode: 0644
+
+ - name: "carputer - owncast - Start container at 0.0.0.0:{{ owncast_web_port }}"
+ shell: "docker-compose -f {{ owncast_working_folder }}/docker-compose.yaml up -d"
+ register: docker_output
+ - debug: |
+ msg="{{ docker_output.stdout_lines }}"
+ msg="{{ docker_output.stderr_lines }}"
\ No newline at end of file
diff --git a/defaults/main.yaml b/defaults/main.yaml
index f143357..d3cfed7 100644
--- a/defaults/main.yaml
+++ b/defaults/main.yaml
@@ -31,7 +31,7 @@ autologin_packages:
# chrome kiosk variables
kiosk_service_templates:
- chrome_resolution: "720,405"
- chrome_website: "http://127.0.0.1:7123/stream"
+ chrome_website: "http://172.30.5.20:7123/stream"
service_name: chrome_webcam
extra_service_configs: |
After=ustreamer.service
@@ -40,7 +40,7 @@ kiosk_service_templates:
extra_chrome_configs: |
--user-data-dir=/opt/chrome/one \
- chrome_resolution: "720,550"
- chrome_website: "http://127.0.0.1:8081"
+ chrome_website: "http://172.30.5.20:8081"
service_name: chrome_timelapse_control
extra_service_configs: ""
user_data_dir: "/opt/chrome/two"
@@ -76,8 +76,13 @@ video_device: "/dev/video0"
resolution: "1920x1080"
ustreamer_port: "7123"
+# owncast vars
+owncast_working_folder: "/opt/cosmos/owncast"
+owncast_web_port: "8082"
+
# other rando vars
cpu_architecture: "amd64"
extra_volumes: ""
+
...
\ No newline at end of file
diff --git a/files/service_control_api/website/styles.css b/files/service_control_api/website/styles.css
index b85b52a..066c1b6 100644
--- a/files/service_control_api/website/styles.css
+++ b/files/service_control_api/website/styles.css
@@ -74,6 +74,11 @@ button:hover {
background: radial-gradient(circle, #003699 0%, #337aff 100%);
color: #bdc3c7; /* Dimmer text color */
}
+.deactivating {
+ background-color: #0d2b2c;
+ background: radial-gradient(circle, #0d2b2c 0%, #123738 100%);
+ color: #bdc3c7; /* Dimmer text color */
+}
.unknown {
background-color: #ec701e;
background: radial-gradient(circle, #c9580d 0%, #ec701e 100%);
diff --git a/tasks/gps_service.yaml b/tasks/gps_service.yaml
index 3cdf972..751df26 100644
--- a/tasks/gps_service.yaml
+++ b/tasks/gps_service.yaml
@@ -1,7 +1,7 @@
---
# Create service Folder
-- name: carputer - gps_service - create photo_refresh folder
+- name: carputer - gps_service - create gps_service_directory folder
file:
path: "{{ gps_service_directory }}"
state: directory
diff --git a/tasks/main.yaml b/tasks/main.yaml
index df5373d..3e342bb 100644
--- a/tasks/main.yaml
+++ b/tasks/main.yaml
@@ -14,15 +14,15 @@
### Bottom Service Control Panel
-#- name: Install Packages
-# apt:
-# name: "{{ item }}"
-# state: present
-# loop: "{{ main_packages }}"
-#
-#- name: Install ustreamer
-# include_tasks: ustreamer.yaml
-#
+- name: Install Packages
+ apt:
+ name: "{{ item }}"
+ state: present
+ loop: "{{ main_packages }}"
+
+- name: Install ustreamer
+ include_tasks: ustreamer.yaml
+
#- name: Install gps_service
# include_tasks: gps_service.yaml
#
@@ -31,14 +31,14 @@
#
#- name: Install photo refresh site
# include_tasks: photo_refresh.yaml
-#
-#- name: Install timelapse service control
-# include_tasks: service_control.yaml
-#
+
+- name: Install timelapse service control
+ include_tasks: service_control.yaml
+
#- name: Install cosmos autologin user
# include_tasks: cosmos_autologin.yaml
#
-- name: Set up Chrome Kiosk Services
- include_tasks: chrome.yaml
+#- name: Set up Chrome Kiosk Services
+# include_tasks: chrome.yaml
...
\ No newline at end of file
diff --git a/tasks/photo_refresh.yaml b/tasks/photo_refresh.yaml
index b8d2c18..8a637b3 100644
--- a/tasks/photo_refresh.yaml
+++ b/tasks/photo_refresh.yaml
@@ -51,10 +51,41 @@
- name: carputer - photo_refresh - Start container at 0.0.0.0:8080
shell: "docker-compose -f {{ photo_refresh_folder }}/docker-compose.yaml up -d"
- register: local_index_output
+ register: docker_output
- debug: |
- msg="{{ local_index_output.stdout_lines }}"
- msg="{{ local_index_output.stderr_lines }}"
+ msg="{{ docker_output.stdout_lines }}"
+ msg="{{ docker_output.stderr_lines }}"
+###############################################
+# set up thumbnail_purge
+###############################################
+
+- name: timelapse - purge thumbnail cron job
+ block:
+
+ - name: timelapse - create purge script
+ copy:
+ dest: "{{ photo_refresh_folder }}/purge_thumbnails.sh"
+ content: |
+ #!/bin/bash
+ TARGET_DIR="{{ working_folder }}/small_thumbs"
+ cd "$TARGET_DIR" || exit
+ # Find all files, sort them by modification time (oldest first), and delete all but the 50 most recent
+ ls -t | tail -n +1000 | while read -r file; do
+ if [ -f "$file" ]; then
+ # echo "Deleting file: $file"
+ rm "$file"
+ fi
+ done
+ mode: 0755
+
+ - name: timelapse - add purge to cron
+ copy:
+ dest: "/etc/cron.d/purge_thumbnails"
+ content: |
+ # This is for deleting the small thumbnails generated by the timelapse
+ # It should run once an hour
+ 00 * * * * root {{ photo_refresh_folder }}/purge_thumbnails.sh
+ mode: 0755
...
\ No newline at end of file
diff --git a/tasks/service_control.yaml b/tasks/service_control.yaml
index ea57b0c..3518c86 100644
--- a/tasks/service_control.yaml
+++ b/tasks/service_control.yaml
@@ -29,8 +29,8 @@
# Copy API Code
- name: carputer - service_control api - copy api code
- copy:
- src: service_control_api/app.py
+ template:
+ src: app-service.py.j2
dest: "{{ service_control_folder }}/app.py"
mode: 0644
@@ -111,12 +111,12 @@
mode: 0644
###############################################
- # Start photo_refresh
+ # Start service_control_website
###############################################
- name: start service_control_website
block:
- - name: set container_name
+ - name: set container variables
set_fact:
container_name: "service_control_website"
container_http_port: "8081"
@@ -129,10 +129,10 @@
- name: "service_control_website - Start container at 0.0.0.0:{{ container_http_port }}"
shell: "docker-compose -f {{ service_control_web_folder }}/docker-compose.yaml up -d"
- register: local_index_output
+ register: docker_output
- debug: |
- msg="{{ local_index_output.stdout_lines }}"
- msg="{{ local_index_output.stderr_lines }}"
+ msg="{{ docker_output.stdout_lines }}"
+ msg="{{ docker_output.stderr_lines }}"
diff --git a/tasks/timelapse.yaml b/tasks/timelapse.yaml
index f754b2a..39601d3 100644
--- a/tasks/timelapse.yaml
+++ b/tasks/timelapse.yaml
@@ -31,4 +31,20 @@
state: stopped
name: timelapse.service
+# create smb for this
+
+- name: timelapse - Copy smb.conf
+ template:
+ src: smb.conf.j2
+ dest: /etc/samba/smb.conf.d/timelapse.conf
+ owner: root
+ group: root
+ mode: 0644
+
+- name: timelapse - Restart smb
+ service:
+ name: smbd
+ state: restarted
+ enabled: yes
+
...
\ No newline at end of file
diff --git a/files/service_control_api/app.py b/templates/app-service.py.j2
similarity index 68%
rename from files/service_control_api/app.py
rename to templates/app-service.py.j2
index 68d4d4b..4738f3e 100644
--- a/files/service_control_api/app.py
+++ b/templates/app-service.py.j2
@@ -3,6 +3,7 @@ import requests
from lxml import html
from flask import Flask, request, jsonify
import json
+import os
app = Flask(__name__)
@@ -52,6 +53,50 @@ def service_status():
except subprocess.CalledProcessError as e:
return {"Error": e.strip('\n')}
+def read_gps_data_file():
+ # Define the path to your file. This is a relative path example. Adjust it as needed.
+ file_path = '{{ gps_service_directory }}/gps_data'
+
+ if os.path.exists(file_path):
+ with open(file_path, 'r') as file:
+ lines = file.readlines()
+
+ # Assuming the data is in a specific format, you can parse it accordingly
+ lat = lines[0].split(':')[1]
+ lon = lines[1].split(':')[1]
+ speed = lines[2].split(':')[1]
+
+ try:
+ lat = float(lat.strip('\n'))
+ lon = float(lon.strip('\n'))
+ speed = float(speed.strip('\n')) * 0.62
+ except:
+ lat = 0
+ lon = 0
+ speed = 0
+
+ # Round latitude and longitude to 5 decimal places at most
+ lat_rounded = round(lat, 3)
+ lon_rounded = round(lon, 3)
+ speed_rounded = round(speed, 1)
+ data = {
+ "lat": lat_rounded,
+ "lon": lon_rounded,
+ "speed": speed_rounded
+ }
+ else:
+ data = {
+ "lat": 37.548,
+ "lon": -121.961,
+ "speed": 0
+ }
+
+ return jsonify(data)
+
+@app.route('/return_gps', methods=['GET'])
+def return_gps():
+ return read_gps_data_file()
+
@app.route('/start', methods=['GET'])
def start():
try:
diff --git a/templates/create_timelapse.sh.j2 b/templates/create_timelapse.sh.j2
index b962baa..05653eb 100644
--- a/templates/create_timelapse.sh.j2
+++ b/templates/create_timelapse.sh.j2
@@ -5,5 +5,6 @@ rm $RUN_FILE
rm $WORKING_DIR/*temp*.jpg
# create timelapse
-/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" -vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4 &
+echo "Creating Timelapse"
+/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" -vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4
diff --git a/templates/index-service_control.php.j2 b/templates/index-service_control.php.j2
index 03b9598..01f0cf6 100644
--- a/templates/index-service_control.php.j2
+++ b/templates/index-service_control.php.j2
@@ -1,4 +1,5 @@
";
// Use file_get_contents or cURL to fetch the API data
- $response = file_get_contents($apiUrl);
-
+ try {
+ $response = file_get_contents($apiUrl);
+ } catch (Exception $e) {
+ $response = '{ "Message": "unknowable", "Status": "unknowable" }';
+ }
if ($response === FALSE) {
$debug_string = $debug_string."Response ERROR!!
";
return "error"; // API error
@@ -52,47 +56,44 @@ function runAPI($submitted_status) {
return isset($data['Status']) ? $data['Status'] : 'unknown';
}
+// | awk '{printf(\"%.5f\n\", $1)}'
+// | awk '{printf(\"%.5f\n\", $1)}'
+
function getGPS(){
- if (!file_exists("{{ gps_service_directory }}/gps_data")) {
- return "No GPS data available.";
- }
+ // check the API
+ $gps_data = file_get_contents("http://172.17.0.1:5000/return_gps");
try {
- $LAT = shell_exec("cat {{ gps_service_directory }}/gps_data | grep lat | cut -d ':' -f 2 | awk '{printf(\"%.5f\n\", $1)}')");
- $LON = shell_exec("cat {{ gps_service_directory }}/gps_data | grep lon | cut -d ':' -f 2 | awk '{printf(\"%.5f\n\", $1)}')");
- $SPEED = floatval(trim(shell_exec("cat {{ gps_service_directory }}/gps_data | grep speed | cut -d ':' -f 2)"))) * 0.62;
- } catch (Exception $e) {
- return "Failed to parse gps_data: ".$e;
- }
+ $gps_data = json_decode($gps_data, true);
- if (is_null($LAT)) {
- return "No GPS data available.";
+ } 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)) {
- return "No GPS data available.";
+ if (is_null($LON) || $LON == 0) {
+ return "No GPS data available - null LON";
}
return $LAT.", ".$LON.", ".$SPEED."mph";
}
-
-// Check if the button was clicked via AJAX request
-// if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-// $button_recent = true;
-// $status_at_submit = $_POST['status'];
-// echo "Set when clicked, second in code - ".$status_at_submit."
";
-// // Get the API result
-// $apiResult = runAPI($status_at_submit);
-// // Return the result as a JSON response
-// echo json_encode(['status' => $apiResult]);
-// exit;
-// }
-
// URL of the external API
$apiUrl = "http://172.17.0.1:5000/status";
// Use file_get_contents to fetch data from the API
-$response = file_get_contents($apiUrl);
+try {
+ $response = file_get_contents($apiUrl);
+} catch (Exception $e) {
+ $response = '{ "Message": "unknowable", "Status": "unknowable" }';
+}
// Check if the request was successful
if ($response === FALSE) {
@@ -132,6 +133,10 @@ switch ($status) {
$button_text = "Service Stopping...";
$button_active = false;
break;
+ case "unknowable":
+ $button_text = "Service Manager Down...";
+ $button_active = false;
+ break;
default:
$button_text = "Error, No Status";
$button_active = false;
diff --git a/templates/purge_thumbnails.sh.j2 b/templates/purge_thumbnails.sh.j2
new file mode 100644
index 0000000..75c354e
--- /dev/null
+++ b/templates/purge_thumbnails.sh.j2
@@ -0,0 +1,10 @@
+#!/bin/bash
+TARGET_DIR="{{ working_folder }}/small_thumbs"
+cd "$TARGET_DIR" || exit
+# Find all files, sort them by modification time (oldest first), and delete all but the 50 most recent
+ls -t | tail -n +51 | while read -r file; do
+ if [ -f "$file" ]; then
+ # echo "Deleting file: $file"
+ rm "$file"
+ fi
+done
\ No newline at end of file
diff --git a/templates/smb.conf.j2 b/templates/smb.conf.j2
new file mode 100644
index 0000000..6331aa6
--- /dev/null
+++ b/templates/smb.conf.j2
@@ -0,0 +1,14 @@
+# timelapse.conf
+# timelapse share folder
+
+
+[timelapse]
+ path = {{ working_folder }}
+ writable = yes
+ read only = no
+ only guest = yes
+ public = yes
+ guest ok = yes
+ guest only = yes
+ guest account = nobody
+ browsable = yes
diff --git a/templates/timelapse.service.j2 b/templates/timelapse.service.j2
index 5d9ceb6..6ae0efc 100644
--- a/templates/timelapse.service.j2
+++ b/templates/timelapse.service.j2
@@ -3,7 +3,7 @@ Description=Timelapse service
After=network.target
[Service]
-ExecStart=/opt/carputer/timelapse/timelapse_service.sh
+ExecStart={{ working_folder }}/timelapse_service.sh
Restart=always
User=root
Group=root
diff --git a/templates/timelapse_service.sh.j2 b/templates/timelapse_service.sh.j2
index d3552e3..f89ef26 100644
--- a/templates/timelapse_service.sh.j2
+++ b/templates/timelapse_service.sh.j2
@@ -1,54 +1,60 @@
#!/bin/bash
trap "source {{ working_folder }}/create_timelapse.sh" SIGINT SIGTERM
-
+echo "Start"
# initialize all the variables
# basic things
BEGIN=$(date +%Y%m%d-%H%M%S)
+echo $BEGIN
WORKING_DIR="{{ working_folder }}/storage/$BEGIN"
-# be greedy about API calls
-WHERES_GALI=$(curl -s http://10.18.1.1:8184/wheres_gali?api_key={{ tesla_api_key }})
-# parse the one API call
-CITY=$(echo $WHERES_GALI | jq .city)
-STATE=$(echo $WHERES_GALI | jq .state)
-ZIPCODE=$(echo $WHERES_GALI | jq .postcode)
-DISPLAY_NAME=$(echo $WHERES_GALI | jq .display_name)
+mkdir -p $WORKING_DIR
+
+if ( nc -w 3 -z 10.18.1.1 8184 2>&1 >/dev/null ); then
+ # be greedy about API calls
+ WHERES_GALI=$(curl -s http://10.18.1.1:8184/wheres_gali?api_key={{ tesla_api_key }})
+ # parse the one API call
+ CITY=$(echo $WHERES_GALI | jq .city)
+ STATE=$(echo $WHERES_GALI | jq .state)
+ ZIPCODE=$(echo $WHERES_GALI | jq .postcode)
+ DISPLAY_NAME=$(echo $WHERES_GALI | jq .display_name)
+ # Generate Status Report
+ echo Timelapse Initiated at $BEGIN >> $WORKING_DIR/info.txt
+ echo Shuttlecraft Galileo located at $CITY, $STATE $ZIPCODE >> $WORKING_DIR/info.txt
+ echo $DISPLAY_NAME >> $WORKING_DIR/info.txt
+else
+ echo "No Gali API Data Available"
+fi
+
RUN_FILE={{ working_folder }}/run
-# Generate Status Report
-mkdir -p $WORKING_DIR
-echo Timelapse Initiated at $BEGIN >> $WORKING_DIR/info.txt
-echo Shuttlecraft Galileo located at $CITY, $STATE $ZIPCODE >> $WORKING_DIR/info.txt
-echo $DISPLAY_NAME >> $WORKING_DIR/info.txt
-
# timelapse creation helpers
-echo "To create timelapse, here's the ffpmeg script" >> $WORKING_DIR/info.txt
-echo "/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \\" >> $WORKING_DIR/info.txt
-echo "-vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4" >> $WORKING_DIR/info.txt
+#echo "To create timelapse, here's the ffpmeg script" >> $WORKING_DIR/info.txt
+#echo "/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \\" >> $WORKING_DIR/info.txt
+#echo "-vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4" >> $WORKING_DIR/info.txt
# there should be a script that can do them all
-echo "/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \\" >> {{ working_folder }}/generate_timelapses.sh
-echo "-vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4" >> {{ working_folder }}/generate_timelapses.sh
+#echo "/bin/ffmpeg -r 30 -pattern_type glob -i "$WORKING_DIR/*.jpg" \\" >> {{ working_folder }}/generate_timelapses.sh
+#echo "-vf "scale=1920x1080" -vcodec libx264 /$WORKING_DIR/00-timelapse.mp4" >> {{ working_folder }}/generate_timelapses.sh
# capture time
touch $RUN_FILE
+echo $RUN_FILE
i=1
+
+
while [ -e $RUN_FILE ]
do
FILENAME=$(printf "img-%05d" "$i")
- # old API based latlon
- #LATLON=$(curl -s http://10.18.1.1:8184/where_is?api_key={{ tesla_api_key }} )
- #LON=$(echo $LATLON | jq .lon)
- #LAT=$(echo $LATLON | jq .lat)
LAT=$(cat {{ gps_service_directory }}/gps_data | grep lat | cut -d ":" -f 2 | awk '{printf("%.5f\n", $1)}')
LON=$(cat {{ gps_service_directory }}/gps_data | grep lon | cut -d ":" -f 2 | awk '{printf("%.5f\n", $1)}')
SPEED_KPH=$(cat {{ gps_service_directory }}/gps_data | grep speed | cut -d ":" -f 2)
- if [ $SPEED_KPH -lt 1 ]; then
+ if [ $SPEED_KPH > 1 ]; then
SPEED_MPH=$(echo "scale=3; $SPEEK_KPH * 0.62" | bc)
else
SPEED_MPH=0
fi
COORDINATES="$LAT, $LON, $SPEED_MPH mph"
curl http://127.0.0.1:7123/snapshot --output $WORKING_DIR/$FILENAME.jpg
-
+ echo $FILENAME
+ echo $COORDINATES
# This variable is for the timestamp
TIME=$(date +%c)
@@ -67,17 +73,14 @@ do
rm $WORKING_DIR/$FILENAME-temp1.jpg $WORKING_DIR/$FILENAME-temp2.jpg
# This is for the tiny pic
- # I'll make one every 5 seconds
# I have 1340x580. i think i will truncate the top
# Calculate the height to trim based on the aspect ratios of the input and output images
- if (( $i % 5 == 0 )); then
- NOW=$(date +%Y%m%d%H%M%S)
- convert $WORKING_DIR/$FILENAME.jpg -gravity North -crop 1920x830+0+260 +repage -resize 1340x580 {{ working_folder }}/small_thumbs/$NOW.jpg
- fi
+ NOW=$(date +%Y%m%d%H%M%S)
+ convert $WORKING_DIR/$FILENAME.jpg -gravity North -crop 1920x830+0+260 +repage -resize 1340x580 {{ working_folder }}/small_thumbs/$NOW.jpg
sleep 1
((i++))
done
-
+# end the loop