WIP: kw1fox-2/software #13
3
.gitignore
vendored
3
.gitignore
vendored
@@ -10,3 +10,6 @@ __pycache__
|
||||
*.jpg
|
||||
*.wav
|
||||
*.pdf
|
||||
|
||||
# Dev
|
||||
.vscode
|
||||
|
||||
BIN
CAD/kw1fox-2/Assembly.FCStd
Normal file
BIN
CAD/kw1fox-2/Assembly.FCStd
Normal file
Binary file not shown.
178418
CAD/kw1fox-2/parts/APRN-pi-3D.step
Normal file
178418
CAD/kw1fox-2/parts/APRN-pi-3D.step
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
CAD/resources/RelayBox.FCStd
Normal file
BIN
CAD/resources/RelayBox.FCStd
Normal file
Binary file not shown.
356317
CAD/resources/raspberry_pi_3_b_plus.stp
Normal file
356317
CAD/resources/raspberry_pi_3_b_plus.stp
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Resources/KW1FOX-1_320x240.png
Normal file
BIN
Resources/KW1FOX-1_320x240.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
Resources/KW1FOX-1_450x240.png
Normal file
BIN
Resources/KW1FOX-1_450x240.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
Resources/KitSuneAero.png
Normal file
BIN
Resources/KitSuneAero.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
BIN
Resources/RadioFont.ttf
Normal file
BIN
Resources/RadioFont.ttf
Normal file
Binary file not shown.
@@ -1,70 +0,0 @@
|
||||
### DISCLAIMER
|
||||
### This is an example Makefile and it MUST be configured to suit your needs.
|
||||
### For detailed explanations about all the available options,
|
||||
### please refer to https://github.com/sudar/Arduino-Makefile/blob/master/arduino-mk-vars.md
|
||||
|
||||
### PROJECT_DIR
|
||||
### This is the path to where you have created/cloned your project
|
||||
PROJECT_DIR = $(shell dirname $(shell pwd))
|
||||
|
||||
### ARDMK_DIR
|
||||
### Path to the Arduino-Makefile directory.
|
||||
ARDMK_DIR = $(PROJECT_DIR)/Arduino-Makefile
|
||||
|
||||
### ARDUINO_DIR
|
||||
### Path to the Arduino application and resources directory.
|
||||
ARDUINO_DIR = /usr/share/arduino
|
||||
|
||||
### USER_LIB_PATH
|
||||
### Path to where the your project's libraries are stored.
|
||||
USER_LIB_PATH := $(realpath $(PROJECT_DIR)/lib)
|
||||
|
||||
### BOARD_TAG & BOARD_SUB
|
||||
### For Arduino IDE 1.0.x
|
||||
### Only BOARD_TAG is needed. It must be set to the board you are currently using. (i.e uno, mega2560, etc.)
|
||||
# BOARD_TAG = mega2560
|
||||
### For Arduino IDE 1.6.x
|
||||
### Both BOARD_TAG and BOARD_SUB are needed. They must be set to the board you are currently using. (i.e BOARD_TAG = uno, mega, etc. & BOARD_SUB = atmega2560, etc.)
|
||||
### Note: for the Arduino Uno, only BOARD_TAG is mandatory and BOARD_SUB can be equal to anything
|
||||
BOARD_TAG = mega
|
||||
BOARD_SUB = atmega2560
|
||||
|
||||
### MONITOR_PORT
|
||||
### The port your board is connected to. Using an '*' tries all the ports and finds the right one. Choose one of the two.
|
||||
MONITOR_PORT = /dev/ttyUSB*
|
||||
# MONITOR_PORT = /dev/ttyACM*
|
||||
|
||||
### MONITOR_BAUDRATE
|
||||
### It must be set to Serial baudrate value you are using.
|
||||
MONITOR_BAUDRATE = 115200
|
||||
|
||||
### AVR_TOOLS_DIR
|
||||
### Path to the AVR tools directory such as avr-gcc, avr-g++, etc.
|
||||
AVR_TOOLS_DIR = /usr
|
||||
|
||||
### AVRDUDE
|
||||
### Path to avrdude directory.
|
||||
AVRDUDE = /usr/bin/avrdude
|
||||
|
||||
### CFLAGS_STD
|
||||
CFLAGS_STD = -std=gnu11
|
||||
|
||||
### CXXFLAGS_STD
|
||||
### You can choose wich ever you like
|
||||
# CXXFLAGS_STD = -std=gnu++11
|
||||
CXXFLAGS_STD = -std=gnu++17
|
||||
|
||||
|
||||
### CPPFLAGS
|
||||
### Flags you might want to set for debugging purpose. Comment to stop.
|
||||
CXXFLAGS += -pedantic -Wall -Wextra
|
||||
LDFLAGS += -fdiagnostics-color
|
||||
|
||||
### OBJDIR
|
||||
### Don't touch this!
|
||||
### This is were you put the binaries you just compile using 'make'
|
||||
CURRENT_DIR = $(shell basename $(CURDIR))
|
||||
OBJDIR = $(PROJECT_DIR)/build/$(CURRENT_DIR)/$(BOARD_TAG)
|
||||
|
||||
### path to Arduino.mk, inside the ARDMK_DIR, don't touch.
|
||||
include $(ARDMK_DIR)/Arduino.mk
|
||||
@@ -1,63 +0,0 @@
|
||||
/* Crawler Slave
|
||||
*
|
||||
* This code runs on the crawler i2c network
|
||||
* and provides a cleaner, less CPU intensive control over PWM devices.
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Servo.h>
|
||||
|
||||
// This servo is used to wipe and clean the camera lens
|
||||
Servo windowWiperServo;
|
||||
|
||||
// Variables populated over i2c from master
|
||||
int id;
|
||||
int val;
|
||||
|
||||
void setup() {
|
||||
// For debugging
|
||||
//Serial.begin(115200);
|
||||
|
||||
// Attach the wiper servo to pin 9
|
||||
windowWiperServo.attach(9);
|
||||
|
||||
// This is the address the pi will speak to us at
|
||||
Wire.begin(0x4);
|
||||
|
||||
// Call receiveEvent when data received
|
||||
Wire.onReceive(receiveEvent);
|
||||
|
||||
// Setup LED
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
//Serial.println("Started");
|
||||
}
|
||||
|
||||
// Just loop to keep the running code alive, and wait for events to happen.
|
||||
void loop() {
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// This method runs when we receive a message
|
||||
void receiveEvent(int n) {
|
||||
Wire.read(); // Remove smbus trash
|
||||
if (true) { // Dont do anything if this is not true
|
||||
id = Wire.read(); // ID of the servo/device to access
|
||||
val = Wire.read(); // Value to assign
|
||||
|
||||
//Serial.println(id);
|
||||
//Serial.println(val);
|
||||
|
||||
switch(id) {
|
||||
case 1:
|
||||
windowWiperServo.write(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevents a bug where if bytes are left in buffer, arduino crashes.
|
||||
while (Wire.available()) {
|
||||
Wire.read();
|
||||
}
|
||||
}
|
||||
8
Software/houston/Makefile
Normal file
8
Software/houston/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
# Joe wrote this
|
||||
|
||||
install:
|
||||
sudo cp qsstv.service /etc/systemd/system/qsstv.service
|
||||
sudo cp robotstreamer.service /etc/systemd/system/robotstreamer.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable qsstv.service
|
||||
sudo systemctl enable robotstreamer.service
|
||||
12
Software/houston/Pipfile
Normal file
12
Software/houston/Pipfile
Normal file
@@ -0,0 +1,12 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
xlib = "*"
|
||||
pillow = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
78
Software/houston/Pipfile.lock
generated
Normal file
78
Software/houston/Pipfile.lock
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "d38f5cc73695023ab5e5dc66a552a8d0bb9d3842a276ca547364ce1d6baaf5b9"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e",
|
||||
"sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595",
|
||||
"sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512",
|
||||
"sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c",
|
||||
"sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477",
|
||||
"sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a",
|
||||
"sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4",
|
||||
"sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e",
|
||||
"sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5",
|
||||
"sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378",
|
||||
"sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a",
|
||||
"sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652",
|
||||
"sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7",
|
||||
"sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a",
|
||||
"sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a",
|
||||
"sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6",
|
||||
"sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165",
|
||||
"sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160",
|
||||
"sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331",
|
||||
"sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b",
|
||||
"sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458",
|
||||
"sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033",
|
||||
"sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8",
|
||||
"sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481",
|
||||
"sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58",
|
||||
"sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7",
|
||||
"sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3",
|
||||
"sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea",
|
||||
"sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34",
|
||||
"sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3",
|
||||
"sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8",
|
||||
"sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581",
|
||||
"sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244",
|
||||
"sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef",
|
||||
"sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0",
|
||||
"sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2",
|
||||
"sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97",
|
||||
"sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.1.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"xlib": {
|
||||
"hashes": [
|
||||
"sha256:60b7cd5d90f5d5922d9ce27b61589c07d970796558d417461db7b66e366bc401",
|
||||
"sha256:8eee67dad83ef4b82bbbfa85d51eeb20c79d12b119fe25aa1d27bd602ff82212"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.21"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
148
Software/houston/RobotStreamer.py
Normal file
148
Software/houston/RobotStreamer.py
Normal file
@@ -0,0 +1,148 @@
|
||||
import time
|
||||
import subprocess as sp
|
||||
|
||||
from Xlib import display, X
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
|
||||
|
||||
class Streamer:
|
||||
def __init__(self):
|
||||
self.x1, self.y1 = 580, 620
|
||||
|
||||
# Create display
|
||||
self.dsp = display.Display(":0")
|
||||
|
||||
# This is the root of the screen
|
||||
self.root = self.dsp.screen().root
|
||||
|
||||
# ffmpeg command
|
||||
|
||||
# ffmpeg --stream_loop -1 -re -i ~/INPUT_FILE -vcodec libx264 -profile:v main -preset:v medium -r 20 -g 60 -keyint_min 60 -sc_threshold 0 -b:v 2500k -maxrate 2500k -bufsize 2500k -sws_flags lanczos+accurate_rnd -acodec aac -b:a 96k -ar 48000 -ac 2 -f flv rtmp://rtmp.robotstreamer.com/live/123?key=123"
|
||||
cmd_out = [
|
||||
"ffmpeg",
|
||||
"-f",
|
||||
"image2pipe",
|
||||
"-vcodec",
|
||||
"png",
|
||||
"-r",
|
||||
"5", # FPS
|
||||
"-i",
|
||||
"-", # Indicated input comes from pipe
|
||||
"-vcodec",
|
||||
"libx264",
|
||||
"-profile:v",
|
||||
"main",
|
||||
"-pix_fmt",
|
||||
"yuv420p",
|
||||
"-preset:v",
|
||||
"medium",
|
||||
"-r",
|
||||
"30",
|
||||
"-g",
|
||||
"60",
|
||||
"-keyint_min",
|
||||
"60",
|
||||
"-sc_threshold",
|
||||
"0",
|
||||
"-b:v",
|
||||
"2500k",
|
||||
"-maxrate",
|
||||
"1500k",
|
||||
"-bufsize",
|
||||
"1500k",
|
||||
"-sws_flags",
|
||||
"lanczos+accurate_rnd",
|
||||
"-acodec",
|
||||
"aac",
|
||||
"-b:a",
|
||||
"96k",
|
||||
"-r",
|
||||
"6",
|
||||
"-ar",
|
||||
"48000",
|
||||
"-ac",
|
||||
"2",
|
||||
"-f",
|
||||
"flv",
|
||||
"rtmp://rtmp.robotstreamer.com/live/topkek",
|
||||
]
|
||||
|
||||
# This is the ffmpeg pipe streamer!
|
||||
self.pipe = sp.Popen(cmd_out, stdin=sp.PIPE)
|
||||
|
||||
# Graphics and resources
|
||||
self.font = ImageFont.truetype(r"../../Resources/RadioFont.ttf", 20)
|
||||
|
||||
def getFrame(self):
|
||||
"""
|
||||
Returns a single cropped sstv video frame
|
||||
"""
|
||||
|
||||
raw = self.root.get_image(0, 0, self.x1, self.y1, X.ZPixmap, 0xFFFFFFFF)
|
||||
image = Image.frombytes("RGB", (self.x1, self.y1), raw.data, "raw", "BGRX")
|
||||
|
||||
image = image.crop((0, 182, self.x1, self.y1))
|
||||
|
||||
return image
|
||||
|
||||
def drawGraphics(self, image: Image):
|
||||
"""
|
||||
Draws graphics and sprites over
|
||||
a frame
|
||||
"""
|
||||
|
||||
frame = Image.new(mode="RGB", size=(1280, 720))
|
||||
|
||||
# Scale and paste
|
||||
image = image.resize((960, 720), Image.ANTIALIAS)
|
||||
frame.paste(image)
|
||||
|
||||
# Populate text, normally this should poll or use shared vars!
|
||||
info = f"""
|
||||
KW1FOX-1
|
||||
Online!
|
||||
Volt: N/A
|
||||
Last comm: {int(time.time())}
|
||||
|
||||
KW1FOX-2
|
||||
Offline.
|
||||
Volt: N/A
|
||||
Last comm: N/A
|
||||
|
||||
KW1FOX-3
|
||||
Offline.
|
||||
Volt: N/A
|
||||
Last comm: N/A
|
||||
|
||||
Currently Showing:
|
||||
KW1FOX-1
|
||||
NOCOM
|
||||
NOMETA
|
||||
"""
|
||||
|
||||
# Draw text
|
||||
draw = ImageDraw.Draw(frame)
|
||||
draw.text((960 + 10, 10), info, font=self.font, align="left")
|
||||
|
||||
return frame
|
||||
|
||||
def stream(self):
|
||||
"""
|
||||
Actually streams!
|
||||
"""
|
||||
|
||||
while True:
|
||||
self.drawGraphics(self.getFrame()).save(self.pipe.stdin, "PNG")
|
||||
|
||||
def __del__(self):
|
||||
self.dsp.close()
|
||||
|
||||
self.pipe.stdin.close()
|
||||
self.pipe.wait()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
myStreamer = Streamer()
|
||||
|
||||
# myStreamer.drawGraphics(Image.open("../../Resources/KW1FOX-1_320x240.png")).show()
|
||||
myStreamer.stream()
|
||||
13
Software/houston/notes.md
Normal file
13
Software/houston/notes.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Notes
|
||||
|
||||
Taking some inspiration from this repo: https://github.com/xssfox/sstv-skimmer/blob/main/Dockerfile
|
||||
|
||||
## Installing qsstv and pulseaudio on server
|
||||
|
||||
Requires `houston` user
|
||||
|
||||
as well as qsstv (obvio)
|
||||
|
||||
and i should prolly install `pulseaudio` as well
|
||||
|
||||
Also, i edited the xorg.conf so it never times out.
|
||||
8
Software/houston/qsstv.service
Normal file
8
Software/houston/qsstv.service
Normal file
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Runs a qsstv instance as houston with houston's config
|
||||
|
||||
[Service]
|
||||
ExecStart=sudo su -l houston -c "/opt/radio/lewis-crawler/Software/houston/sstv.sh"
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
199
Software/houston/qsstv_9.0.conf
Normal file
199
Software/houston/qsstv_9.0.conf
Normal file
@@ -0,0 +1,199 @@
|
||||
[CW]
|
||||
cwWPM=12
|
||||
cwtext=
|
||||
cwtone=800
|
||||
|
||||
[DIRECTORIES]
|
||||
audioPath=/home/parallels/qsstv/audio/
|
||||
docURL=http://users.telenet.be/on4qz/qsstv/manual
|
||||
rxDRMImagesPath=/tmp/rx_images
|
||||
rxSSTVImagesPath=/tmp/rx_images
|
||||
saveTXimages=false
|
||||
templatesPath=/home/parallels/qsstv/templates/
|
||||
txDRMImagesPath=/home/parallels/qsstv/tx_drm/
|
||||
txSSTVImagesPath=/home/parallels/qsstv/tx_sstv/
|
||||
txStockImagesPath=/home/parallels/qsstv/tx_stock/
|
||||
|
||||
[DRMPROFILE]
|
||||
drmPF1Bandwidth=0
|
||||
drmPF1Interleave=0
|
||||
drmPF1Mode=0
|
||||
drmPF1Name=Profile 1
|
||||
drmPF1Protection=0
|
||||
drmPF1QAM=0
|
||||
drmPF1ReedSolomon=0
|
||||
drmPF2Bandwidth=0
|
||||
drmPF2Interleave=0
|
||||
drmPF2Mode=0
|
||||
drmPF2Name=Profile 2
|
||||
drmPF2Protection=0
|
||||
drmPF2QAM=0
|
||||
drmPF2ReedSolomon=0
|
||||
drmPF3Bandwidth=0
|
||||
drmPF3Interleave=0
|
||||
drmPF3Mode=0
|
||||
drmPF3Name=Profile 3
|
||||
drmPF3Protection=0
|
||||
drmPF3QAM=0
|
||||
drmPF3ReedSolomon=0
|
||||
|
||||
[FREQSELECT]
|
||||
additionalCommand=
|
||||
additionalCommandHex=false
|
||||
frequencyList=@Invalid()
|
||||
modeList=@Invalid()
|
||||
passBandList=@Invalid()
|
||||
sbModeList=@Invalid()
|
||||
|
||||
[FTPCONFIG]
|
||||
addExtension=false
|
||||
enableFTP=false
|
||||
ftpDefaultImageFormat=png
|
||||
ftpLogin=
|
||||
ftpNumImages=30
|
||||
ftpPassword=
|
||||
ftpPort=21
|
||||
ftpRemoteDRMDirectory=
|
||||
ftpRemoteHost=
|
||||
ftpRemoteSSTVDirectory=
|
||||
ftpSaveFormat=0
|
||||
|
||||
[GUI]
|
||||
backGroundColor=@Variant(\0\0\0\x43\x1\xff\xff\0\0VV\xe6\xe6\0\0)
|
||||
confirmClose=true
|
||||
confirmDeletion=true
|
||||
galleryColumns=4
|
||||
galleryRows=4
|
||||
imageBackGroundColor=@Variant(\0\0\0\x43\x1\xff\xff\x80\x80\x80\x80\x80\x80\0\0)
|
||||
imageStretch=true
|
||||
lowRes=false
|
||||
slowCPU=false
|
||||
|
||||
[HYBRID]
|
||||
enableHybridNotify=true
|
||||
enableHybridRx=true
|
||||
hybridFtpHybridFilesDirectory=HybridFiles1
|
||||
hybridFtpLogin=
|
||||
hybridFtpPassword=
|
||||
hybridFtpPort=21
|
||||
hybridFtpRemoteDirectory=
|
||||
hybridFtpRemoteHost=
|
||||
hybridNotifyDir=RxOkNotifications1
|
||||
onlineStatusDir=OnlineCallsigns1
|
||||
|
||||
[MAIN]
|
||||
transmissionModeIndex=0
|
||||
windowHeight=768
|
||||
windowWidth=1024
|
||||
windowX=0
|
||||
windowY=0
|
||||
|
||||
[PERSONAL]
|
||||
callsign=NOCALL
|
||||
firstname=NOFIRSTNAME
|
||||
lastname=NONAME
|
||||
locator=NOLOCATOR
|
||||
onlinestatusenabled=true
|
||||
onlinestatustext=
|
||||
qth=NOWHERE
|
||||
|
||||
[REPEATER]
|
||||
repeaterAcknowledge=
|
||||
repeaterEnabled=false
|
||||
repeaterIdleTemplate=
|
||||
repeaterIdleTxMode=0
|
||||
repeaterImage1=
|
||||
repeaterImage2=
|
||||
repeaterImage3=
|
||||
repeaterImage4=
|
||||
repeaterImageInterval=10
|
||||
repeaterImageSize=10
|
||||
repeaterTemplate=
|
||||
repeaterTxDelay=5
|
||||
repeaterTxMode=0
|
||||
|
||||
[RX]
|
||||
autoSave=true
|
||||
autoSlantAdjust=true
|
||||
defaultImageFormat=png
|
||||
minCompletion=50
|
||||
sensitivity=2
|
||||
sstvModeIndexRx=10
|
||||
|
||||
[SOUND]
|
||||
alsaSelected=false
|
||||
inputAudioDevice=default -- Playback/recording through the PulseAudio sound server
|
||||
outputAudioDevice=default -- Playback/recording through the PulseAudio sound server
|
||||
pttToneOtherChannel=false
|
||||
pulseSelected=true
|
||||
recordingSize=100
|
||||
rxclock=48000
|
||||
soundRoutingInput=0
|
||||
soundRoutingOutput=0
|
||||
swapChannel=false
|
||||
txclock=48000
|
||||
|
||||
[SPECTRUM]
|
||||
avg=0.9
|
||||
maxdb=-25
|
||||
range=35
|
||||
|
||||
[TX]
|
||||
compressedSize=5000
|
||||
drmBandWith=0
|
||||
drmInterLeaver=0
|
||||
drmProtection=0
|
||||
drmQAM=0
|
||||
drmReedSolomon=0
|
||||
drmRobMode=0
|
||||
sstvModeIndexTx=0
|
||||
templateIndex=-1
|
||||
useCW=false
|
||||
useHybrid=false
|
||||
useTemplate=false
|
||||
useVOX=false
|
||||
|
||||
[WATERFALL]
|
||||
bsrWF=BSR
|
||||
endBinWF=END BIN
|
||||
endPicWF=END PIC
|
||||
endRepeaterWF=END RPT
|
||||
fixWF=FIX
|
||||
sampleString=Sample Text
|
||||
startBinWF=START BIN
|
||||
startPicWF=START PIC
|
||||
startRepeaterWF=START RPT
|
||||
wfBold=false
|
||||
wfFont=Aharoni CLM
|
||||
wfFontSize=12
|
||||
|
||||
[Waterfall]
|
||||
text1=rest
|
||||
text2=
|
||||
text3=
|
||||
text4=
|
||||
|
||||
[logging]
|
||||
deduplicate=true
|
||||
maskBA="@Variant(\0\0\0\r\0\0\0,\0\0\0\0\0\0)"
|
||||
|
||||
[radio1]
|
||||
XMLRPCPort=7362
|
||||
activeDTR=false
|
||||
activeRTS=true
|
||||
baudrate=9600
|
||||
civAddress=
|
||||
databits=8
|
||||
enableCAT=false
|
||||
enableSerialPTT=false
|
||||
enableXMLRPC=false
|
||||
handshake=None
|
||||
nactiveDTR=false
|
||||
nactiveRTS=false
|
||||
parity=None
|
||||
pttSerialPort=/dev/ttyS0
|
||||
pttType=1
|
||||
radioModel="29001 ADAT www.adat.ch,ADT-200A"
|
||||
serialPort=/dev/ttyS0
|
||||
stopbits=1
|
||||
txOnDelay=0
|
||||
9
Software/houston/robotstreamer.service
Normal file
9
Software/houston/robotstreamer.service
Normal file
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Runs the robotstreamer stream
|
||||
|
||||
[Service]
|
||||
ExecStart=sudo su -l houston -c "/opt/radio/lewis-crawler/Software/houston/stream.sh"
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
12
Software/houston/sstv.sh
Executable file
12
Software/houston/sstv.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Runs all the required fluff for spawning qsstv with notifing and stuff.
|
||||
|
||||
# Make tempdirs
|
||||
mkdir -p /tmp/sstv_images
|
||||
|
||||
# Copy config file
|
||||
cp /opt/radio/lewis-crawler/Software/houston/qsstv_9.0.conf ~/.config/ON4QZ/qsstv_9.0.conf
|
||||
|
||||
# Spawn qsstv
|
||||
xinit -geometry =1280x960+0+0 -fn 8x13 -j -fg white -bg black qsstv -- -nocursor
|
||||
5
Software/houston/stream.sh
Executable file
5
Software/houston/stream.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Runs the robotstream
|
||||
cd /opt/radio/lewis-crawler/Software/houston/ && pipenv run python RobotStreamer.py
|
||||
|
||||
15
Software/kw1fox-2/Pipfile
Normal file
15
Software/kw1fox-2/Pipfile
Normal file
@@ -0,0 +1,15 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pysstv = "*"
|
||||
pillow = "*"
|
||||
pyaudio = "*"
|
||||
pi-ina219 = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.10"
|
||||
121
Software/kw1fox-2/Pipfile.lock
generated
Normal file
121
Software/kw1fox-2/Pipfile.lock
generated
Normal file
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "377233137977bb1db670b363317a6a2619ddd8544f91531a5224826022fa3e23"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.10"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"adafruit-gpio": {
|
||||
"hashes": [
|
||||
"sha256:d6465b92c866c51ca8f3bc1e8f2ec36f5ccdb46d0fd54101c1109756d4a2dcd0"
|
||||
],
|
||||
"version": "==1.0.3"
|
||||
},
|
||||
"adafruit-pureio": {
|
||||
"hashes": [
|
||||
"sha256:2caf22fb07c7f771d83267f331a76cde314723f884a9570ea6f768730c87a879"
|
||||
],
|
||||
"markers": "python_full_version >= '3.5.0'",
|
||||
"version": "==1.1.9"
|
||||
},
|
||||
"mock": {
|
||||
"hashes": [
|
||||
"sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62",
|
||||
"sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==4.0.3"
|
||||
},
|
||||
"pi-ina219": {
|
||||
"hashes": [
|
||||
"sha256:29524cc308c56a5c483f551187923d3e167f2d39a29dc64c731ba7a8e04d022b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01ce45deec9df310cbbee11104bae1a2a43308dd9c317f99235b6d3080ddd66e",
|
||||
"sha256:0c51cb9edac8a5abd069fd0758ac0a8bfe52c261ee0e330f363548aca6893595",
|
||||
"sha256:17869489de2fce6c36690a0c721bd3db176194af5f39249c1ac56d0bb0fcc512",
|
||||
"sha256:21dee8466b42912335151d24c1665fcf44dc2ee47e021d233a40c3ca5adae59c",
|
||||
"sha256:25023a6209a4d7c42154073144608c9a71d3512b648a2f5d4465182cb93d3477",
|
||||
"sha256:255c9d69754a4c90b0ee484967fc8818c7ff8311c6dddcc43a4340e10cd1636a",
|
||||
"sha256:35be4a9f65441d9982240e6966c1eaa1c654c4e5e931eaf580130409e31804d4",
|
||||
"sha256:3f42364485bfdab19c1373b5cd62f7c5ab7cc052e19644862ec8f15bb8af289e",
|
||||
"sha256:3fddcdb619ba04491e8f771636583a7cc5a5051cd193ff1aa1ee8616d2a692c5",
|
||||
"sha256:463acf531f5d0925ca55904fa668bb3461c3ef6bc779e1d6d8a488092bdee378",
|
||||
"sha256:4fe29a070de394e449fd88ebe1624d1e2d7ddeed4c12e0b31624561b58948d9a",
|
||||
"sha256:55dd1cf09a1fd7c7b78425967aacae9b0d70125f7d3ab973fadc7b5abc3de652",
|
||||
"sha256:5a3ecc026ea0e14d0ad7cd990ea7f48bfcb3eb4271034657dc9d06933c6629a7",
|
||||
"sha256:5cfca31ab4c13552a0f354c87fbd7f162a4fafd25e6b521bba93a57fe6a3700a",
|
||||
"sha256:66822d01e82506a19407d1afc104c3fcea3b81d5eb11485e593ad6b8492f995a",
|
||||
"sha256:69e5ddc609230d4408277af135c5b5c8fe7a54b2bdb8ad7c5100b86b3aab04c6",
|
||||
"sha256:6b6d4050b208c8ff886fd3db6690bf04f9a48749d78b41b7a5bf24c236ab0165",
|
||||
"sha256:7a053bd4d65a3294b153bdd7724dce864a1d548416a5ef61f6d03bf149205160",
|
||||
"sha256:82283af99c1c3a5ba1da44c67296d5aad19f11c535b551a5ae55328a317ce331",
|
||||
"sha256:8782189c796eff29dbb37dd87afa4ad4d40fc90b2742704f94812851b725964b",
|
||||
"sha256:8d79c6f468215d1a8415aa53d9868a6b40c4682165b8cb62a221b1baa47db458",
|
||||
"sha256:97bda660702a856c2c9e12ec26fc6d187631ddfd896ff685814ab21ef0597033",
|
||||
"sha256:a325ac71914c5c043fa50441b36606e64a10cd262de12f7a179620f579752ff8",
|
||||
"sha256:a336a4f74baf67e26f3acc4d61c913e378e931817cd1e2ef4dfb79d3e051b481",
|
||||
"sha256:a598d8830f6ef5501002ae85c7dbfcd9c27cc4efc02a1989369303ba85573e58",
|
||||
"sha256:a5eaf3b42df2bcda61c53a742ee2c6e63f777d0e085bbc6b2ab7ed57deb13db7",
|
||||
"sha256:aea7ce61328e15943d7b9eaca87e81f7c62ff90f669116f857262e9da4057ba3",
|
||||
"sha256:af79d3fde1fc2e33561166d62e3b63f0cc3e47b5a3a2e5fea40d4917754734ea",
|
||||
"sha256:c24f718f9dd73bb2b31a6201e6db5ea4a61fdd1d1c200f43ee585fc6dcd21b34",
|
||||
"sha256:c5b0ff59785d93b3437c3703e3c64c178aabada51dea2a7f2c5eccf1bcf565a3",
|
||||
"sha256:c7110ec1701b0bf8df569a7592a196c9d07c764a0a74f65471ea56816f10e2c8",
|
||||
"sha256:c870193cce4b76713a2b29be5d8327c8ccbe0d4a49bc22968aa1e680930f5581",
|
||||
"sha256:c9efef876c21788366ea1f50ecb39d5d6f65febe25ad1d4c0b8dff98843ac244",
|
||||
"sha256:de344bcf6e2463bb25179d74d6e7989e375f906bcec8cb86edb8b12acbc7dfef",
|
||||
"sha256:eb1b89b11256b5b6cad5e7593f9061ac4624f7651f7a8eb4dfa37caa1dfaa4d0",
|
||||
"sha256:ed742214068efa95e9844c2d9129e209ed63f61baa4d54dbf4cf8b5e2d30ccf2",
|
||||
"sha256:f401ed2bbb155e1ade150ccc63db1a4f6c1909d3d378f7d1235a44e90d75fb97",
|
||||
"sha256:fb89397013cf302f282f0fc998bb7abf11d49dcff72c8ecb320f76ea6e2c5717"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.1.0"
|
||||
},
|
||||
"pyaudio": {
|
||||
"hashes": [
|
||||
"sha256:0d92f6a294565260a282f7c9a0b0d309fc8cc988b5ee5b50645634ab9e2da7f7",
|
||||
"sha256:259bb9c1363be895b4f9a97e320a6017dd06bc540728c1a04eb4a7b6fe75035b",
|
||||
"sha256:2a19bdb8ec1445b4f3e4b7b109e0e4cec1fd1f1ce588592aeb6db0b58d4fb3b0",
|
||||
"sha256:51b558d1b28c68437b53218279110db44f69f3f5dd3d81859f569a4a96962bdc",
|
||||
"sha256:589bfad2c615dd4b5d3757e763019c42ab82f06fba5cae64ec02fd7f5ae407ed",
|
||||
"sha256:8f89075b4844ea94dde0c951c2937581c989fabd4df09bfd3f075035f50955df",
|
||||
"sha256:93bfde30e0b64e63a46f2fd77e85c41fd51182a4a3413d9edfaf9ffaa26efb74",
|
||||
"sha256:cf1543ba50bd44ac0d0ab5c035bb9c3127eb76047ff12235149d9adf86f532b6",
|
||||
"sha256:f78d543a98b730e64621ebf7f3e2868a79ade0a373882ef51c0293455ffa8e6e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.11"
|
||||
},
|
||||
"pysstv": {
|
||||
"hashes": [
|
||||
"sha256:a0306ff80bb25f28c4455c9dd75dd8cebbb3fa7d77b87af18e6cf2b86ade6b47"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.4"
|
||||
},
|
||||
"spidev": {
|
||||
"hashes": [
|
||||
"sha256:8a7f5c289f161ea2ac4697fa8a10918232c990678dd0053084b3c43b1363910d"
|
||||
],
|
||||
"version": "==3.5"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
3
Software/kw1fox-2/README.md
Normal file
3
Software/kw1fox-2/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# KW1FOX-2 Software
|
||||
|
||||
This is the software for KW1FOX-2, the APRS/SSTV relay station.
|
||||
0
Software/kw1fox-2/__init__.py
Normal file
0
Software/kw1fox-2/__init__.py
Normal file
29
Software/kw1fox-2/kw1fox-2.py
Normal file
29
Software/kw1fox-2/kw1fox-2.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from PIL import Image
|
||||
|
||||
from pysstv.color import Robot36
|
||||
|
||||
from tools.pyaudio import PyAudioSSTV
|
||||
|
||||
|
||||
class kw1fox2:
|
||||
def __init__(self, sim=False):
|
||||
# Lets us automate more testing locally by having a program-wide sim mode.
|
||||
self.sim = sim
|
||||
|
||||
img = Image.open("../../Resources/KW1FOX-1_320x240.png")
|
||||
self.sstv = Robot36(img, 44100, 16)
|
||||
self.sstv.vox_enabled = True
|
||||
|
||||
self.sstv.write_wav("Mysstv.wav")
|
||||
|
||||
def run(self):
|
||||
PyAudioSSTV(self.sstv).execute()
|
||||
|
||||
def take_snapshot(self):
|
||||
if not self.sim:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
station = kw1fox2()
|
||||
station.run()
|
||||
0
Software/kw1fox-2/tools/__init__.py
Normal file
0
Software/kw1fox-2/tools/__init__.py
Normal file
43
Software/kw1fox-2/tools/pyaudio.py
Normal file
43
Software/kw1fox-2/tools/pyaudio.py
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Example code from here: https://github.com/dnet/pySSTV/blob/master/pysstv/examples/pyaudio_sstv.py
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import division
|
||||
from pysstv.sstv import SSTV
|
||||
from time import sleep
|
||||
from itertools import islice
|
||||
import struct, pyaudio
|
||||
|
||||
|
||||
class PyAudioSSTV(object):
|
||||
def __init__(self, sstv):
|
||||
self.pa = pyaudio.PyAudio()
|
||||
self.sstv = sstv
|
||||
self.fmt = "<" + SSTV.BITS_TO_STRUCT[sstv.bits]
|
||||
|
||||
def __del__(self):
|
||||
self.pa.terminate()
|
||||
|
||||
def execute(self):
|
||||
self.sampler = self.sstv.gen_samples()
|
||||
stream = self.pa.open(
|
||||
format=self.pa.get_format_from_width(self.sstv.bits // 8),
|
||||
channels=1,
|
||||
rate=self.sstv.samples_per_sec,
|
||||
output=True,
|
||||
stream_callback=self.callback,
|
||||
)
|
||||
stream.start_stream()
|
||||
while stream.is_active():
|
||||
sleep(0.5)
|
||||
stream.stop_stream()
|
||||
stream.close()
|
||||
|
||||
def callback(self, in_data, frame_count, time_info, status):
|
||||
frames = "".join(
|
||||
struct.pack(self.fmt, b) for b in islice(self.sampler, frame_count)
|
||||
)
|
||||
return frames, pyaudio.paContinue
|
||||
@@ -1,5 +0,0 @@
|
||||
wiper_servo:
|
||||
pin: 17
|
||||
min_pulse: 0.000544
|
||||
max_pulse: 0.0024
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=Crawler service overseer, manages running main crawler software
|
||||
After=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/python /srv/crawler/crawler.py
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,2 +0,0 @@
|
||||
PySSTV
|
||||
picamera
|
||||
@@ -1,87 +0,0 @@
|
||||
from shutil import copyfile
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
from pysstv import color
|
||||
|
||||
import logging as log
|
||||
|
||||
try:
|
||||
from picamera import PiCamera
|
||||
except ModuleNotFoundError:
|
||||
log.info("Running in simulator mode")
|
||||
|
||||
|
||||
def take_photo():
|
||||
# This def is meant to take a photograph from the robot,
|
||||
# it should include all steps and error checking to raise the mast
|
||||
# Take the photo, and put the mast down.
|
||||
|
||||
# Copy in the test pattern png (if photo process errors out, this will be used instead)
|
||||
log.debug('Copying test pattern.')
|
||||
copyfile('photos/TEST_PATTERN.jpg', 'working/working.jpg')
|
||||
|
||||
# Software to take the photo should be here
|
||||
#copyfile('photos/camera_latest.jpg', 'working/working.jpg')
|
||||
log.debug('Initalizing camera.')
|
||||
try:
|
||||
camera = PiCamera()
|
||||
log.info('Saving photo.')
|
||||
camera.capture('working/working.jpg')
|
||||
except NameError:
|
||||
log.info("Running in simulator mode, not replacing test pattern")
|
||||
|
||||
def mark_photo():
|
||||
log.info('Opening photo for viewing.')
|
||||
raw_img = Image.open("working/working.jpg") # Open the current working image
|
||||
log.info('Resizing image.')
|
||||
img = raw_img.resize((320, 240), Image.ANTIALIAS) # resize it for the radio
|
||||
|
||||
log.info('Drawing on image.')
|
||||
if False:
|
||||
TINT_COLOR = (255, 255, 255) # White text bg
|
||||
TEXT_COLOR = (0,0,0)
|
||||
else:
|
||||
TINT_COLOR = (0, 0, 0) # Black text bg
|
||||
TEXT_COLOR = (255,255,255)
|
||||
TRANSPARENCY = .25 # Degree of transparency, 0-100%
|
||||
OPACITY = int(255 * TRANSPARENCY)
|
||||
overlay = Image.new('RGBA', img.size, TINT_COLOR+(0,))
|
||||
|
||||
draw = ImageDraw.Draw(overlay)
|
||||
#bigfont = ImageFont.truetype(r'C:\Users\System-Pc\Desktop\arial.ttf', 20)
|
||||
#smallfont = ImageFont.truetype(r'C:\Users\System-Pc\Desktop\arial.ttf', 17)
|
||||
|
||||
draw.rectangle(((0, 0), (90, 20)), fill=TINT_COLOR+(OPACITY,))
|
||||
#draw.text((0, 0),"KW1FOX",TEXT_COLOR,font=bigfont) # Draw KW1FOX in the top left
|
||||
|
||||
draw.rectangle(((0, 40), (83, 80)), fill=TINT_COLOR+(OPACITY,))
|
||||
#draw.text((0, 40),"day: 25.2",TEXT_COLOR,font=smallfont)
|
||||
#draw.text((0, 60),"Volt: 13.8",TEXT_COLOR,font=smallfont)
|
||||
#draw.text((0, 80),"Miles: 1.02",TEXT_COLOR,font=smallfont)
|
||||
|
||||
log.info('Converting image color.')
|
||||
img = img.convert("RGBA")
|
||||
img = Image.alpha_composite(img, overlay)
|
||||
img = img.convert("RGB")
|
||||
img.save('working/working.jpg') # Save the working image
|
||||
return img
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.basicConfig(level=log.DEBUG)
|
||||
|
||||
# Take photograph.
|
||||
log.info('Taking Photograph')
|
||||
take_photo() # Saves a photograph to the working/working.jpg location
|
||||
log.info('Done taking photo.')
|
||||
|
||||
# Draw neccicary text on photo
|
||||
log.info('Drawing on photo.')
|
||||
radio_photo = mark_photo() # draws text on working/working.jpg and returns a PIL image
|
||||
log.info('Done drawing on photo.')
|
||||
|
||||
log.info('Creating slowscan.')
|
||||
slowscan = color.Robot36(radio_photo, 48000, 16) # Image, rate, bits
|
||||
#slowscan = color.MartinM1(radio_photo, 48000, 16) # Image, rate, bits
|
||||
log.info('Saving out slowscan.')
|
||||
slowscan.write_wav('working/working.wav')
|
||||
|
||||
#sstv('working/working.png', 'working/radio.wav', mode='Robot36')
|
||||
@@ -1,73 +0,0 @@
|
||||
from discord_webhook import DiscordWebhook
|
||||
from picamera import PiCamera
|
||||
from time import sleep
|
||||
from gps import *
|
||||
from smbus import SMBus
|
||||
import time
|
||||
|
||||
addr = 0x4 # bus address
|
||||
bus = SMBus(1) # indicates /dev/ic2-1
|
||||
|
||||
numb = 1
|
||||
|
||||
def writeData(value):
|
||||
byteValue = StringToBytes(value)
|
||||
bus.write_i2c_block_data(addr,0x00,byteValue) #first byte is 0=command byte.. just is.
|
||||
return -1
|
||||
|
||||
|
||||
def StringToBytes(val):
|
||||
retVal = []
|
||||
for c in val:
|
||||
retVal.append(ord(c))
|
||||
return retVal
|
||||
|
||||
try:
|
||||
for _x in range (0, 2):
|
||||
for i in range(78, 130):
|
||||
writeData("WIPE-" + str(i))
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 78, -1):
|
||||
writeData("WIPE-" + str(i))
|
||||
time.sleep(0.02)
|
||||
except OSError:
|
||||
print("Could not speak to ardujmemo")
|
||||
|
||||
def get_uptime():
|
||||
with open('/proc/uptime', 'r') as f:
|
||||
uptime_seconds = float(f.readline().split()[0])
|
||||
|
||||
return uptime_seconds
|
||||
|
||||
def getPositionData(gps):
|
||||
location = [None]
|
||||
while(location[0] == None):
|
||||
print("Trying again")
|
||||
nx = gpsd.next()
|
||||
# For a list of all supported classes and fields refer to:
|
||||
# https://gpsd.gitlab.io/gpsd/gpsd_json.html
|
||||
if nx['class'] == 'TPV':
|
||||
latitude = getattr(nx,'lat', "Unknown")
|
||||
longitude = getattr(nx,'lon', "Unknown")
|
||||
#print "Your position: lon = " + str(longitude) + ", lat = " + str(latitude)
|
||||
location = [latitude, longitude]
|
||||
return location
|
||||
|
||||
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)
|
||||
|
||||
loc = getPositionData(gpsd)
|
||||
|
||||
webhookURL = "https://discord.com/api/webhooks/856609966404534272/TR9tnLq2sIGZoOeADNswmGRNlzBcqM5aKihfU6snVTP9WhSSoVVvi7nT6i-ZfZS7Hcqm"
|
||||
|
||||
print(loc[0])
|
||||
print(loc[1])
|
||||
webhook = DiscordWebhook(url=webhookURL, content="Uptime: " + str( round( ((get_uptime() / 60) / 60 ), 2 )) + " hours. Lat is " + str(loc[0]) + ", long is " + str(loc[1]))
|
||||
|
||||
camera = PiCamera()
|
||||
sleep(3) # let iso settle out
|
||||
camera.capture('still.jpg')
|
||||
|
||||
with open("still.jpg", "rb") as f:
|
||||
webhook.add_file(file=f.read(), filename='still.jpg')
|
||||
response = webhook.execute() # Hit send
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
servoPIN = 17
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(servoPIN, GPIO.OUT)
|
||||
|
||||
p = GPIO.PWM(servoPIN, 50) # GPIO 17 for PWM with 50Hz
|
||||
p.start(2.5) # Initialization
|
||||
try:
|
||||
while True:
|
||||
p.ChangeDutyCycle(10)
|
||||
time.sleep(2)
|
||||
p.ChangeDutyCycle(2.5)
|
||||
time.sleep(2)
|
||||
except KeyboardInterrupt:
|
||||
p.stop()
|
||||
GPIO.cleanup()
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import smbus
|
||||
import time
|
||||
import struct
|
||||
|
||||
# for RPI version 1, use bus = smbus.SMBus(0)
|
||||
bus = smbus.SMBus(1)
|
||||
|
||||
# This is the address we setup in the Arduino Program
|
||||
address = 0x04
|
||||
|
||||
try:
|
||||
for _x in range (0, 2):
|
||||
for i in range(78, 130):
|
||||
bus.write_i2c_block_data(address, 0, [1, i])
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 78, -1):
|
||||
bus.write_i2c_block_data(address, 0, [1, i])
|
||||
time.sleep(0.02)
|
||||
except OSError:
|
||||
print("Could not speak to ardujmemo")
|
||||
@@ -1,35 +0,0 @@
|
||||
# Raspberry Pi Master for Arduino Slave
|
||||
# i2c_master_pi.py
|
||||
# Connects to Arduino via I2C
|
||||
|
||||
# DroneBot Workshop 2019
|
||||
# https://dronebotworkshop.com
|
||||
|
||||
from smbus import SMBus
|
||||
import time
|
||||
|
||||
addr = 0x8 # bus address
|
||||
bus = SMBus(1) # indicates /dev/ic2-1
|
||||
|
||||
numb = 1
|
||||
|
||||
print ("Enter num")
|
||||
|
||||
for _x in range (0, 4):
|
||||
for i in range(76, 130):
|
||||
bus.write_byte(addr, i)
|
||||
time.sleep(0.02)
|
||||
for i in range(130, 76, -1):
|
||||
bus.write_byte(addr, i)
|
||||
time.sleep(0.02)
|
||||
|
||||
#while numb == 1:
|
||||
#
|
||||
# ledstate = input(">>>> ")
|
||||
#
|
||||
# if ledstate == "1":
|
||||
# bus.write_byte(addr, 0x1) # switch it on
|
||||
# elif ledstate == "0":
|
||||
# bus.write_byte(addr, 0x0) # switch it on
|
||||
# else:
|
||||
# numb = 0
|
||||
@@ -1,12 +0,0 @@
|
||||
import RPi.GPIO as GPIO # Import Raspberry Pi GPIO library
|
||||
from time import sleep # Import the sleep function from the time module
|
||||
|
||||
GPIO.setwarnings(False) # Ignore warning for now
|
||||
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
|
||||
GPIO.setup(12, GPIO.OUT, initial=GPIO.LOW) # Set pin 8 to be an output pin and set initial value to low (off)
|
||||
|
||||
while True: # Run forever
|
||||
GPIO.output(12, GPIO.HIGH) # Turn on
|
||||
sleep(1) # Sleep for 1 second
|
||||
GPIO.output(12, GPIO.LOW) # Turn off
|
||||
sleep(1) # Sleep for 1 second
|
||||
Reference in New Issue
Block a user