first commit
This commit is contained in:
Executable
+3
@@ -0,0 +1,3 @@
|
||||
*.pyc
|
||||
.DS_Store
|
||||
status.wav
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Armel FAUVEAU
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Executable
+997
@@ -0,0 +1,997 @@
|
||||
###############################################################################
|
||||
#
|
||||
# Generic Logic event handlers
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# This is the namespace in which all functions and variables below will exist.
|
||||
#
|
||||
namespace eval Logic {
|
||||
|
||||
|
||||
#
|
||||
# A variable used to store a timestamp for the last identification.
|
||||
#
|
||||
variable prev_ident 0;
|
||||
|
||||
#
|
||||
# A constant that indicates the minimum time in seconds to wait between two
|
||||
# identifications. Manual and long identifications is not affected.
|
||||
#
|
||||
variable min_time_between_ident 120;
|
||||
|
||||
#
|
||||
# Short and long identification intervals. They are setup from config
|
||||
# variables below.
|
||||
#
|
||||
variable short_ident_interval 0;
|
||||
variable long_ident_interval 0;
|
||||
|
||||
variable short_voice_id_enable 1
|
||||
variable short_cw_id_enable 0
|
||||
variable short_announce_enable 0
|
||||
variable short_announce_file ""
|
||||
|
||||
variable long_voice_id_enable 1
|
||||
variable long_cw_id_enable 0
|
||||
variable long_announce_enable 0
|
||||
variable long_announce_file ""
|
||||
|
||||
#
|
||||
# The ident_only_after_tx variable indicates if identification is only to
|
||||
# occur after the node has transmitted. The variable is setup below from the
|
||||
# configuration variable with the same name.
|
||||
# The need_ident variable indicates if identification is needed.
|
||||
#
|
||||
variable ident_only_after_tx 0;
|
||||
variable need_ident 0;
|
||||
|
||||
#
|
||||
# List of functions that should be called periodically. Use the
|
||||
# addMinuteTickSubscriber and addSecondTickSubscriber functions to
|
||||
# add subscribers.
|
||||
#
|
||||
variable minute_tick_subscribers [list];
|
||||
variable second_tick_subscribers [list];
|
||||
|
||||
#
|
||||
# Contains the ID of the last receiver that indicated squelch activity
|
||||
#
|
||||
variable sql_rx_id "?";
|
||||
|
||||
#
|
||||
# Executed when the SvxLink software is started
|
||||
#
|
||||
proc startup {} {
|
||||
#playMsg "Core" "online"
|
||||
#send_short_ident
|
||||
|
||||
variable room;
|
||||
|
||||
set fp [open "/etc/spotnik/network" "r"];
|
||||
set room [string tolower [gets $fp]]
|
||||
|
||||
puts "**** Salon: $room ****";
|
||||
|
||||
if {"$room" != "default"} {
|
||||
playMsg "RRF" "S$room"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a specified module could not be found
|
||||
# module_id - The numeric ID of the module
|
||||
#
|
||||
proc no_such_module {module_id} {
|
||||
playMsg "Core" "no_such_module";
|
||||
playNumber $module_id;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a manual identification is initiated with the * DTMF code
|
||||
#
|
||||
proc manual_identification {} {
|
||||
global mycall;
|
||||
global report_ctcss;
|
||||
global active_module;
|
||||
global loaded_modules;
|
||||
variable CFG_TYPE;
|
||||
variable prev_ident;
|
||||
|
||||
set epoch [clock seconds];
|
||||
set hour [clock format $epoch -format "%k"];
|
||||
regexp {([1-5]?\d)$} [clock format $epoch -format "%M"] -> minute;
|
||||
set prev_ident $epoch;
|
||||
|
||||
playMsg "Core" "online";
|
||||
spellWord $mycall;
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
playMsg "Core" "repeater";
|
||||
}
|
||||
playSilence 250;
|
||||
playMsg "Core" "the_time_is";
|
||||
playTime $hour $minute;
|
||||
playSilence 250;
|
||||
if {$report_ctcss > 0} {
|
||||
playMsg "Core" "pl_is";
|
||||
playFrequency $report_ctcss
|
||||
playSilence 300;
|
||||
}
|
||||
if {$active_module != ""} {
|
||||
playMsg "Core" "active_module";
|
||||
playMsg $active_module "name";
|
||||
playSilence 250;
|
||||
set func "::";
|
||||
append func $active_module "::status_report";
|
||||
if {"[info procs $func]" ne ""} {
|
||||
$func;
|
||||
}
|
||||
} else {
|
||||
foreach module [split $loaded_modules " "] {
|
||||
set func "::";
|
||||
append func $module "::status_report";
|
||||
if {"[info procs $func]" ne ""} {
|
||||
$func;
|
||||
}
|
||||
}
|
||||
}
|
||||
playMsg "Default" "press_0_for_help"
|
||||
playSilence 250;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a short identification should be sent
|
||||
# hour - The hour on which this identification occur
|
||||
# minute - The minute on which this identification occur
|
||||
#
|
||||
proc send_short_ident {{hour -1} {minute -1}} {
|
||||
global mycall;
|
||||
global report_ctcss;
|
||||
variable CFG_TYPE;
|
||||
variable short_announce_file
|
||||
variable short_announce_enable
|
||||
variable short_voice_id_enable
|
||||
variable short_cw_id_enable
|
||||
|
||||
# Play voice id if enabled
|
||||
if {$short_voice_id_enable} {
|
||||
puts "Playing short voice ID"
|
||||
spellWord $mycall;
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
playMsg "Core" "repeater";
|
||||
}
|
||||
playSilence 500;
|
||||
if {$report_ctcss > 0} {
|
||||
playMsg "Core" "pl_is";
|
||||
playFrequency $report_ctcss
|
||||
playSilence 300;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# Play announcement file if enabled
|
||||
if {$short_announce_enable} {
|
||||
puts "Playing short announce"
|
||||
if [file exist "$short_announce_file"] {
|
||||
playFile "$short_announce_file"
|
||||
playSilence 500
|
||||
}
|
||||
}
|
||||
|
||||
# Play CW id if enabled
|
||||
if {$short_cw_id_enable} {
|
||||
puts "Playing short CW ID"
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
set call "$mycall/R"
|
||||
CW::play $call
|
||||
} else {
|
||||
CW::play $mycall
|
||||
}
|
||||
playSilence 500;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a long identification (e.g. hourly) should be sent
|
||||
# hour - The hour on which this identification occur
|
||||
# minute - The minute on which this identification occur
|
||||
#
|
||||
proc send_long_ident {hour minute} {
|
||||
global mycall;
|
||||
global loaded_modules;
|
||||
global active_module;
|
||||
global report_ctcss;
|
||||
variable CFG_TYPE;
|
||||
variable long_announce_file
|
||||
variable long_announce_enable
|
||||
variable long_voice_id_enable
|
||||
variable long_cw_id_enable
|
||||
|
||||
# Play the voice ID if enabled
|
||||
if {$long_voice_id_enable} {
|
||||
puts "Playing Long voice ID"
|
||||
spellWord $mycall;
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
playMsg "Core" "repeater";
|
||||
}
|
||||
playSilence 500;
|
||||
if {$report_ctcss > 0} {
|
||||
playMsg "Core" "pl_is";
|
||||
playFrequency $report_ctcss
|
||||
playSilence 300;
|
||||
}
|
||||
playMsg "Core" "the_time_is";
|
||||
playSilence 100;
|
||||
playTime $hour $minute;
|
||||
playSilence 500;
|
||||
|
||||
# Call the "status_report" function in all modules if no module is active
|
||||
if {$active_module == ""} {
|
||||
foreach module [split $loaded_modules " "] {
|
||||
set func "::";
|
||||
append func $module "::status_report";
|
||||
if {"[info procs $func]" ne ""} {
|
||||
$func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playSilence 500;
|
||||
}
|
||||
|
||||
# Play announcement file if enabled
|
||||
if {$long_announce_enable} {
|
||||
puts "Playing long announce"
|
||||
if [file exist "$long_announce_file"] {
|
||||
playFile "$long_announce_file"
|
||||
playSilence 500
|
||||
}
|
||||
}
|
||||
|
||||
# Play CW id if enabled
|
||||
if {$long_cw_id_enable} {
|
||||
puts "Playing long CW ID"
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
set call "$mycall/R"
|
||||
CW::play $call
|
||||
} else {
|
||||
CW::play $mycall
|
||||
}
|
||||
playSilence 100
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the squelch have just closed and the RGR_SOUND_DELAY timer has
|
||||
# expired.
|
||||
#
|
||||
proc send_rgr_sound {} {
|
||||
variable sql_rx_id
|
||||
|
||||
if {$sql_rx_id != "?"} {
|
||||
# 150 CPM, 1000 Hz, -4 dBFS
|
||||
CW::play $sql_rx_id 150 1000 -4
|
||||
set sql_rx_id "?"
|
||||
} else {
|
||||
CW::play " K" 150 600 -8
|
||||
}
|
||||
playSilence 100
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an empty macro command (i.e. D#) has been entered.
|
||||
#
|
||||
proc macro_empty {} {
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an entered macro command could not be found
|
||||
#
|
||||
proc macro_not_found {} {
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a macro syntax error occurs (configuration error).
|
||||
#
|
||||
proc macro_syntax_error {} {
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the specified module in a macro command is not found
|
||||
# (configuration error).
|
||||
#
|
||||
proc macro_module_not_found {} {
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the activation of the module specified in the macro command
|
||||
# failed.
|
||||
#
|
||||
proc macro_module_activation_failed {} {
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a macro command is executed that requires a module to
|
||||
# be activated but another module is already active.
|
||||
#
|
||||
proc macro_another_active_module {} {
|
||||
global active_module;
|
||||
|
||||
playMsg "Core" "operation_failed";
|
||||
playMsg "Core" "active_module";
|
||||
playMsg $active_module "name";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an unknown DTMF command is entered
|
||||
# cmd - The command string
|
||||
#
|
||||
proc unknown_command {cmd} {
|
||||
spellWord $cmd;
|
||||
playMsg "Core" "unknown_command";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when an entered DTMF command failed
|
||||
# cmd - The command string
|
||||
#
|
||||
proc command_failed {cmd} {
|
||||
spellWord $cmd;
|
||||
playMsg "Core" "operation_failed";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a link to another logic core is activated.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc activating_link {name} {
|
||||
if {[string length $name] > 0} {
|
||||
playMsg "Core" "activating_link_to";
|
||||
spellWord $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a link to another logic core is deactivated.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc deactivating_link {name} {
|
||||
if {[string length $name] > 0} {
|
||||
playMsg "Core" "deactivating_link_to";
|
||||
spellWord $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to deactivate a link to another logic core but the
|
||||
# link is not currently active.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc link_not_active {name} {
|
||||
if {[string length $name] > 0} {
|
||||
playMsg "Core" "link_not_active_to";
|
||||
spellWord $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to activate a link to another logic core but the
|
||||
# link is already active.
|
||||
# name - The name of the link
|
||||
#
|
||||
proc link_already_active {name} {
|
||||
if {[string length $name] > 0} {
|
||||
playMsg "Core" "link_already_active_to";
|
||||
spellWord $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed each time the transmitter is turned on or off
|
||||
# is_on - Set to 1 if the transmitter is on or 0 if it's off
|
||||
#
|
||||
proc transmit {is_on} {
|
||||
#puts "Turning the transmitter $is_on";
|
||||
variable prev_ident;
|
||||
variable need_ident;
|
||||
if {$is_on && ([clock seconds] - $prev_ident > 5)} {
|
||||
set need_ident 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed each time the squelch is opened or closed
|
||||
# rx_id - The ID of the RX that the squelch opened/closed on
|
||||
# is_open - Set to 1 if the squelch is open or 0 if it's closed
|
||||
#
|
||||
proc squelch_open {rx_id is_open} {
|
||||
variable sql_rx_id;
|
||||
#puts "The squelch is $is_open on RX $rx_id";
|
||||
set sql_rx_id $rx_id;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a DTMF digit has been received
|
||||
# digit - The detected DTMF digit
|
||||
# duration - The duration, in milliseconds, of the digit
|
||||
#
|
||||
# Return 1 to hide the digit from further processing in SvxLink or
|
||||
# return 0 to make SvxLink continue processing as normal.
|
||||
#
|
||||
proc dtmf_digit_received {digit duration} {
|
||||
#puts "DTMF digit \"$digit\" detected with duration $duration ms";
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when a DTMF command has been received
|
||||
# cmd - The command
|
||||
#
|
||||
# Return 1 to hide the command from further processing is SvxLink or
|
||||
# return 0 to make SvxLink continue processing as normal.
|
||||
#
|
||||
# This function can be used to implement your own custom commands or to disable
|
||||
# DTMF commands that you do not want users to execute.
|
||||
proc dtmf_cmd_received {cmd} {
|
||||
#global active_module
|
||||
|
||||
# Example: Ignore all commands starting with 3 in the EchoLink module.
|
||||
# Allow commands that have four or more digits.
|
||||
#if {$active_module == "EchoLink"} {
|
||||
# if {[string length $cmd] < 4 && [string index $cmd 0] == "3"} {
|
||||
# puts "Ignoring random connect command for module EchoLink: $cmd"
|
||||
# return 1
|
||||
# }
|
||||
#}
|
||||
|
||||
# Handle the "force core command" mode where a command is forced to be
|
||||
# executed by the core command processor instead of by an active module.
|
||||
# The "force core command" mode is entered by prefixing a command by a star.
|
||||
#if {$active_module != "" && [string index $cmd 0] != "*"} {
|
||||
# return 0
|
||||
#}
|
||||
#if {[string index $cmd 0] == "*"} {
|
||||
# set cmd [string range $cmd 1 end]
|
||||
#}
|
||||
|
||||
# Example: Custom command executed when DTMF 99 is received
|
||||
#if {$cmd == "99"} {
|
||||
# puts "Executing external command"
|
||||
|
||||
# playMsg "Core" "online"
|
||||
# exec ls &
|
||||
# return 1
|
||||
#}
|
||||
|
||||
proc sayIP {} {
|
||||
set result [exec /etc/spotnik/getIP]
|
||||
puts "$result"
|
||||
|
||||
regexp "(\[0-9]{1,3})\.(\[0-9]{1,3})\.(\[0-9]{1,3})\.(\[0-9]{1,3})" $result all first second third fourth
|
||||
|
||||
playSilence 100
|
||||
playNumber $first
|
||||
playSilence 100
|
||||
playMsg "default" "dash"
|
||||
playSilence 100
|
||||
playNumber $second
|
||||
playSilence 100
|
||||
playMsg "default" "dash"
|
||||
playSilence 100
|
||||
playNumber $third
|
||||
playSilence 100
|
||||
playMsg "default" "dash"
|
||||
playSilence 100
|
||||
playNumber $fourth
|
||||
|
||||
playSilence 500;
|
||||
}
|
||||
|
||||
# internet test
|
||||
proc sayInternetStatus {} {
|
||||
if {[catch {exec ping -c 1 google.com} result] == 0} {
|
||||
puts "Internet Online Passed"
|
||||
playSilence 100
|
||||
playMsg "Core" "online"
|
||||
} else {
|
||||
puts "Internet Disconnected"
|
||||
#playMsg "MetarInfo" "not"
|
||||
#playMsg "Core" "online"
|
||||
#playSilence 500;
|
||||
playSilence 100
|
||||
playMsg "EchoLink" "link"
|
||||
playMsg "EchoLink" "disconnected"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Speak network IPs
|
||||
if {$cmd == "93"} {
|
||||
sayIP
|
||||
return 1
|
||||
}
|
||||
|
||||
# Say if online or offline
|
||||
if {$cmd == "939"} {
|
||||
sayInternetStatus
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
if {$cmd == "94"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /usr/bin/nmcli con up SPOTNIK &
|
||||
exec nohup /usr/bin route del default &
|
||||
return 1
|
||||
}
|
||||
|
||||
# Mode Déconnecté du réseau, Autonome Relais seulement
|
||||
|
||||
if {$cmd == "95"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.default &
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
# 96 SvxReflector RRF
|
||||
|
||||
if {$cmd == "96"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.rrf &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 97 SvxReflector FON
|
||||
|
||||
if {$cmd == "97"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.fon &
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
# 98 Salon Technique
|
||||
if {$cmd == "98"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.tec &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 99 Salon International
|
||||
if {$cmd == "99"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.int &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 100 Salon Bavardage
|
||||
if {$cmd == "100"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.bav &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 101 Salon Local
|
||||
if {$cmd == "101"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.loc &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 102 salon Sat
|
||||
if {$cmd == "102"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.sat &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 103 Echolink
|
||||
if {$cmd == "103"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.el &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 104 Regional a creer
|
||||
if {$cmd == "104"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec nohup /etc/spotnik/restart.reg &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 200 Raptor start and stop
|
||||
if {$cmd == "200"} {
|
||||
puts "Executing external command"
|
||||
exec nohup /opt/RRFRaptor/RRFRaptor.sh &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 201 Raptor quick scan
|
||||
if {$cmd == "201"} {
|
||||
puts "Executing external command"
|
||||
exec /opt/RRFRaptor/RRFRaptor.sh scan
|
||||
return 1
|
||||
}
|
||||
|
||||
# 202 Raptor sound
|
||||
if {$cmd == "202"} {
|
||||
if { [file exists /tmp/RRFRaptor_status.tcl] } {
|
||||
source "/tmp/RRFRaptor_status.tcl"
|
||||
if {$RRFRaptor == "ON"} {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/active.wav
|
||||
} else {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/desactive.wav
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
# 203 Raptor quick scan sound
|
||||
if {$cmd == "203"} {
|
||||
if { [file exists /tmp/RRFRaptor_scan.tcl] } {
|
||||
source "/tmp/RRFRaptor_scan.tcl"
|
||||
if {$RRFRaptor == "None"} {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/qso_ko.wav
|
||||
} else {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/qso_ok.wav
|
||||
if {$RRFRaptor == "RRF"} {
|
||||
playFile /etc/spotnik/Srrf.wav
|
||||
} elseif {$RRFRaptor == "FON"} {
|
||||
playFile /etc/spotnik/Sfon.wav
|
||||
} elseif {$RRFRaptor == "TECHNIQUE"} {
|
||||
playFile /etc/spotnik/Stec.wav
|
||||
} elseif {$RRFRaptor == "INTERNATIONAL"} {
|
||||
playFile /etc/spotnik/Sint.wav
|
||||
} elseif {$RRFRaptor == "LOCAL"} {
|
||||
playFile /etc/spotnik/Sloc.wav
|
||||
} elseif {$RRFRaptor == "BAVARDAGE"} {
|
||||
playFile /etc/spotnik/Sbav.wav
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
# 1000 Reboot
|
||||
|
||||
if {$cmd == "1000"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec reboot &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 1001 halt
|
||||
|
||||
if {$cmd == "1001"} {
|
||||
puts "Executing external command"
|
||||
playMsg "Core" "online"
|
||||
exec halt &
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Executed once every whole minute. Don't put any code here directly
|
||||
# Create a new function and add it to the timer tick subscriber list
|
||||
# by using the function addMinuteTickSubscriber.
|
||||
#
|
||||
proc every_minute {} {
|
||||
variable minute_tick_subscribers;
|
||||
#puts [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"];
|
||||
foreach subscriber $minute_tick_subscribers {
|
||||
$subscriber;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed once every whole minute. Don't put any code here directly
|
||||
# Create a new function and add it to the timer tick subscriber list
|
||||
# by using the function addSecondTickSubscriber.
|
||||
#
|
||||
proc every_second {} {
|
||||
variable second_tick_subscribers;
|
||||
#puts [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"];
|
||||
foreach subscriber $second_tick_subscribers {
|
||||
$subscriber;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Deprecated: Use the addMinuteTickSubscriber function instead
|
||||
#
|
||||
proc addTimerTickSubscriber {func} {
|
||||
puts "*** WARNING: Calling deprecated TCL event handler addTimerTickSubcriber."
|
||||
puts " Use addMinuteTickSubscriber instead"
|
||||
addMinuteTickSubscriber $func;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Use this function to add a function to the list of functions that
|
||||
# should be executed once every whole minute. This is not an event
|
||||
# function but rather a management function.
|
||||
#
|
||||
proc addMinuteTickSubscriber {func} {
|
||||
variable minute_tick_subscribers;
|
||||
lappend minute_tick_subscribers $func;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Use this function to add a function to the list of functions that
|
||||
# should be executed once every second. This is not an event
|
||||
# function but rather a management function.
|
||||
#
|
||||
proc addSecondTickSubscriber {func} {
|
||||
variable second_tick_subscribers;
|
||||
lappend second_tick_subscribers $func;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Should be executed once every whole minute to check if it is time to
|
||||
# identify. Not exactly an event function. This function handle the
|
||||
# identification logic and call the send_short_ident or send_long_ident
|
||||
# functions when it is time to identify.
|
||||
#
|
||||
proc checkPeriodicIdentify {} {
|
||||
variable prev_ident;
|
||||
variable short_ident_interval;
|
||||
variable long_ident_interval;
|
||||
variable min_time_between_ident;
|
||||
variable ident_only_after_tx;
|
||||
variable need_ident;
|
||||
global logic_name;
|
||||
|
||||
if {$short_ident_interval == 0} {
|
||||
return;
|
||||
}
|
||||
|
||||
set now [clock seconds];
|
||||
set hour [clock format $now -format "%k"];
|
||||
regexp {([1-5]?\d)$} [clock format $now -format "%M"] -> minute;
|
||||
|
||||
set short_ident_now \
|
||||
[expr {($hour * 60 + $minute) % $short_ident_interval == 0}];
|
||||
set long_ident_now 0;
|
||||
if {$long_ident_interval != 0} {
|
||||
set long_ident_now \
|
||||
[expr {($hour * 60 + $minute) % $long_ident_interval == 0}];
|
||||
}
|
||||
|
||||
if {$long_ident_now} {
|
||||
puts "$logic_name: Sending long identification...";
|
||||
send_long_ident $hour $minute;
|
||||
set prev_ident $now;
|
||||
set need_ident 0;
|
||||
} else {
|
||||
if {$now - $prev_ident < $min_time_between_ident} {
|
||||
return;
|
||||
}
|
||||
if {$ident_only_after_tx && !$need_ident} {
|
||||
return;
|
||||
}
|
||||
|
||||
if {$short_ident_now} {
|
||||
puts "$logic_name: Sending short identification...";
|
||||
send_short_ident $hour $minute;
|
||||
set prev_ident $now;
|
||||
set need_ident 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the QSO recorder is being activated
|
||||
#
|
||||
proc activating_qso_recorder {} {
|
||||
playMsg "Core" "activating";
|
||||
playMsg "Core" "qso_recorder";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the QSO recorder is being deactivated
|
||||
#
|
||||
proc deactivating_qso_recorder {} {
|
||||
playMsg "Core" "deactivating";
|
||||
playMsg "Core" "qso_recorder";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to deactivate the QSO recorder even though it's
|
||||
# not active
|
||||
#
|
||||
proc qso_recorder_not_active {} {
|
||||
playMsg "Core" "qso_recorder";
|
||||
playMsg "Core" "not_active";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when trying to activate the QSO recorder even though it's
|
||||
# already active
|
||||
#
|
||||
proc qso_recorder_already_active {} {
|
||||
playMsg "Core" "qso_recorder";
|
||||
playMsg "Core" "already_active";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the timeout kicks in to activate the QSO recorder
|
||||
#
|
||||
proc qso_recorder_timeout_activate {} {
|
||||
playMsg "Core" "timeout"
|
||||
playMsg "Core" "activating";
|
||||
playMsg "Core" "qso_recorder";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the timeout kicks in to deactivate the QSO recorder
|
||||
#
|
||||
proc qso_recorder_timeout_deactivate {} {
|
||||
playMsg "Core" "timeout"
|
||||
playMsg "Core" "deactivating";
|
||||
playMsg "Core" "qso_recorder";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the user is requesting a language change
|
||||
#
|
||||
proc set_language {lang_code} {
|
||||
global logic_name;
|
||||
puts "$logic_name: Setting language $lang_code (NOT IMPLEMENTED)";
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the user requests a list of available languages
|
||||
#
|
||||
proc list_languages {} {
|
||||
global logic_name;
|
||||
puts "$logic_name: Available languages: (NOT IMPLEMENTED)";
|
||||
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Executed when the node is being brought online or offline
|
||||
#
|
||||
proc logic_online {online} {
|
||||
global mycall
|
||||
variable CFG_TYPE
|
||||
|
||||
if {$online} {
|
||||
playMsg "Core" "online";
|
||||
spellWord $mycall;
|
||||
if {$CFG_TYPE == "Repeater"} {
|
||||
playMsg "Core" "repeater";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Main program
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
if [info exists CFG_SHORT_IDENT_INTERVAL] {
|
||||
if {$CFG_SHORT_IDENT_INTERVAL > 0} {
|
||||
set short_ident_interval $CFG_SHORT_IDENT_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if [info exists CFG_LONG_IDENT_INTERVAL] {
|
||||
if {$CFG_LONG_IDENT_INTERVAL > 0} {
|
||||
set long_ident_interval $CFG_LONG_IDENT_INTERVAL;
|
||||
if {$short_ident_interval == 0} {
|
||||
set short_ident_interval $long_ident_interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if [info exists CFG_IDENT_ONLY_AFTER_TX] {
|
||||
if {$CFG_IDENT_ONLY_AFTER_TX > 0} {
|
||||
set ident_only_after_tx $CFG_IDENT_ONLY_AFTER_TX;
|
||||
}
|
||||
}
|
||||
|
||||
if [info exists CFG_SHORT_ANNOUNCE_ENABLE] {
|
||||
set short_announce_enable $CFG_SHORT_ANNOUNCE_ENABLE
|
||||
}
|
||||
|
||||
if [info exists CFG_SHORT_ANNOUNCE_FILE] {
|
||||
set short_announce_file $CFG_SHORT_ANNOUNCE_FILE
|
||||
}
|
||||
|
||||
if [info exists CFG_SHORT_VOICE_ID_ENABLE] {
|
||||
set short_voice_id_enable $CFG_SHORT_VOICE_ID_ENABLE
|
||||
}
|
||||
|
||||
if [info exists CFG_SHORT_CW_ID_ENABLE] {
|
||||
set short_cw_id_enable $CFG_SHORT_CW_ID_ENABLE
|
||||
}
|
||||
|
||||
if [info exists CFG_LONG_ANNOUNCE_ENABLE] {
|
||||
set long_announce_enable $CFG_LONG_ANNOUNCE_ENABLE
|
||||
}
|
||||
|
||||
if [info exists CFG_LONG_ANNOUNCE_FILE] {
|
||||
set long_announce_file $CFG_LONG_ANNOUNCE_FILE
|
||||
}
|
||||
|
||||
if [info exists CFG_LONG_VOICE_ID_ENABLE] {
|
||||
set long_voice_id_enable $CFG_LONG_VOICE_ID_ENABLE
|
||||
}
|
||||
|
||||
if [info exists CFG_LONG_CW_ID_ENABLE] {
|
||||
set long_cw_id_enable $CFG_LONG_CW_ID_ENABLE
|
||||
}
|
||||
|
||||
|
||||
# end of namespace
|
||||
}
|
||||
|
||||
#
|
||||
# This file has not been truncated
|
||||
#
|
||||
Executable
+191
@@ -0,0 +1,191 @@
|
||||
# RRFRaptor
|
||||
Le RRFRaptor analyse le trafic sur le réseau [RRF](https://f5nlg.wordpress.com/2015/12/28/nouveau-reseau-french-repeater-network/) (Réseau des Répéteurs Francophones) et gère automatiquement les QSY de votre Spotnik afin de lui faire rejoindre automatiquement le salon sur lequel il y a de l'activité. Attention, __il n'est pas recommandé de l'installer sur un relais__ en permanence. Par contre, il est parfaitement adapté à un usage personnel.
|
||||
|
||||
> Pour ma part, j'active néanmoins le RRFRaptor sur le F1ZPX situé en JN18du, entre 22h05 et 06h05, période généralement assez calme sur le RRF.
|
||||
|
||||
# Principe de fonctionnement
|
||||
Une fois le RRFRaptor lancé, tant qu'il y a de l'activité sur le salon sur lequel vous êtes, rien ne se passe. Le RRFRaptor reste en sommeil.
|
||||
|
||||
Si l'activité retombe, au bout d'une certaine temporisation paramétrable, le RRFRaptor va s'activer et commencer à analyser le trafic sur l'ensemble du réseau RRF à la recherche de QSO sur les autres salons.
|
||||
|
||||
Si le trafic reprend entre temps sur le salon sur lequel vous étiez, évidemment, la temporisation redémarre à zéro et le RRFRaptor retombe en sommeil.
|
||||
|
||||
Par contre, si le trafic ne reprend pas et que le RRFRaptor détecte de l'activité sur un autre salon, alors il va automatiquement faire basculer votre Spotnik sur celui ci.
|
||||
|
||||
# Installation
|
||||
|
||||
## Installation du RRFRaptor
|
||||
|
||||
Commencez par ouvrir une connexion SSH sur votre Spotnik.
|
||||
|
||||
### Etape 1 - Récupération du code
|
||||
|
||||
Depuis votre connexion SSH, lancez les commandes suivantes :
|
||||
|
||||
`cd /opt`
|
||||
|
||||
Puis,
|
||||
|
||||
`git clone https://github.com/armel/RRFRaptor.git`
|
||||
|
||||
### Etape 2 - Installation des dépendances
|
||||
|
||||
Si nécessaire, il faut également procéder à l'installation de quelques paquets complémentaires. Rassurez-vous, ce sera rapide. Toujours depuis votre connexion SSH, lancez les commandes suivantes :
|
||||
|
||||
`sudo apt-get install python-pip`
|
||||
|
||||
`sudo pip install requests`
|
||||
|
||||
### Etape 3 - Ajout des codes DTMF
|
||||
|
||||
Il est possible d'activer et de désactiver le RRFRaptor par un simple code DTMF.
|
||||
|
||||
Si vous n'êtes pas familier avec les fichiers de paramétrages de __SvxLink__, il vous suffit de copier le fichier `Logic.tcl` que j'ai déjà modifié pour vous. Donc, depuis votre connexion SSH, lancer les commandes suivantes :
|
||||
|
||||
`mv /usr/share/svxlink/events.d/local/Logic.tcl /usr/share/svxlink/events.d/local/Logic.tcl.bak`
|
||||
|
||||
|
||||
`cp /opt/RRFRaptor/Logic.tcl /usr/share/svxlink/events.d/local/Logic.tcl`
|
||||
|
||||
La première va faire une sauvegarde de votre fichier `Logic.tcl` (renommé en `Logic.tcl.bak` au cas ou). Et la seconde va copier le fichier `Logic.tcl` modifié afin de prendre en charge le RRFRaptor.
|
||||
|
||||
Le RRFRaptor pourra désormais être activé ou désactivé en envoyant le code DTMF __200__.
|
||||
|
||||
### Etape 4 - Redémarrage de SvxLink
|
||||
|
||||
Enfin, pour finir, redémarrez __SvxLink__ à l'aide de la commande suivante :
|
||||
|
||||
`/etc/spotnik/restart`
|
||||
|
||||
Et voilà, c'est tout ;) Vous êtes pret à utiliser le RRFRaptor !
|
||||
|
||||
## Lancement du RRFRaptor
|
||||
|
||||
Le plus simple est de lancer le RRFRaptor en CLI (ligne de commande). Toujours depuis une connexion SSH,
|
||||
|
||||
- pour activer le RRFRaptor : `/opt/RRFRaptor/RRFRaptor.sh start`
|
||||
- pour désactiver le RRFRaptor : `/opt/RRFRaptor/RRFRaptor.sh stop`
|
||||
|
||||
Sinon, vous pouvez également activer ou désactiver le RRFRaptor à l'aide du code DTMF __200__.
|
||||
|
||||
Dans tous les cas, une annonce vocale vous informera de l'activation ou de la désactivation du RRFRaptor.
|
||||
|
||||
Une fois activé, en l'absence d'activité durant 1 minute (par défaut), le RRFRaptor va commencer à analyser le trafic sur l'ensemble du réseau RRF à la recherche de QSO sur les autres salons et gérer lui même les QSY.
|
||||
|
||||
## Mode scan rapide
|
||||
|
||||
Le RRFRaptor dispose également d'une fonctionnalité de _scan rapide_. Cela permet de savoir si un QSO est en cours sur un salon, via une annonce vocale. __Il n'est pas nécessaire que le RRFRaptor soit activé pour que cette fonctionnalité soit utilisable__. On peut donc lancer un _scan rapide_ à tous moments.
|
||||
|
||||
En CLI (ligne de commande), depuis une connexion SSH, lancez la commande suivante :
|
||||
|
||||
`/opt/RRFRaptor/RRFRaptor.sh scan`
|
||||
|
||||
Sinon, vous pouvez également utiliser le code DTMF __201__.
|
||||
|
||||
> S'il n'est pas forcément recommandé d'activer en permanence le RRFRaptor sur un relais, cette fonctionnalité de __scan rapide__ peut s'avérer très intéressante partout. Un seul code DTMF peut renseigner les OM sur les QSO en cours sur les autres salons. À eux, si le RRFRaptor n'est pas activé, de gérer les QSY.
|
||||
|
||||
# Paramétrages fins
|
||||
|
||||
## Changer les paramétrages par défaut
|
||||
|
||||
Vous pouvez évidemment éditer le fichier `/opt/RRFRaptor/RRFRaptor.sh` afin de changer la durée de la temporisation par défaut (option `--sleep`).
|
||||
|
||||
>L'option `--debug` présente juste un intérêt en phase de développement. Inutile de l'activer.
|
||||
|
||||
## Ne pas prendre en compte certains salons
|
||||
|
||||
Vous pouvez éditer le fichier `/opt/RRFRaptor/settings.py` et modifier la variable `valid_room` (ligne 20) avec la liste des salons que vous voulez surveiller.
|
||||
|
||||
## Lancer le RRFRaptor au démarrage du Spotnik
|
||||
|
||||
Il est évidemment possible de lancer le RRFRaptor au démarrage du Spotnik. Il suffit d'éditer le fichier `/etc/rc.local` et d'y ajouter les lignes suivantes, juste __avant__ le `exit 0` qui termine le script :
|
||||
|
||||
```
|
||||
## demarrage Raptor
|
||||
/opt/RRFRaptor/RRFRaptor.sh start
|
||||
```
|
||||
|
||||
## Mettre à jour la version du RRFRaptor
|
||||
|
||||
Depuis votre connexion SSH, lancez les commandes suivantes :
|
||||
|
||||
`cd /opt/RRFRaptor`
|
||||
|
||||
`git pull`
|
||||
|
||||
`mv /usr/share/svxlink/events.d/local/Logic.tcl /usr/share/svxlink/events.d/local/Logic.tcl.bak`
|
||||
|
||||
`cp /opt/RRFRaptor/Logic.tcl /usr/share/svxlink/events.d/local/Logic.tcl`
|
||||
|
||||
`/etc/spotnik/restart`
|
||||
|
||||
Et voilà, votre version est à jour.
|
||||
|
||||
## Modifier les codes DTMF par défaut
|
||||
|
||||
Si vous le souhaitez, vous pouvez modifier les codes DTMF par défaut et les adapter suivant vos besoins. Pour se faire, éditer le fichier `/usr/share/svxlink/events.d/local/Logic.tcl` à l'aide de votre éditeur préféré. Recherchez les blocs concernant les codes DTMF (vers les lignes 600...). Ajoutez et / ou modifiez les 4 nouveaux blocs ci dessous en les adaptant à votre convenance :
|
||||
|
||||
```
|
||||
# 200 Raptor start and stop
|
||||
if {$cmd == "200"} {
|
||||
puts "Executing external command"
|
||||
exec nohup /opt/RRFRaptor/RRFRaptor.sh &
|
||||
return 1
|
||||
}
|
||||
|
||||
# 201 Raptor quick scan
|
||||
if {$cmd == "201"} {
|
||||
puts "Executing external command"
|
||||
exec /opt/RRFRaptor/RRFRaptor.sh scan
|
||||
return 1
|
||||
}
|
||||
|
||||
# 202 Raptor sound
|
||||
if {$cmd == "202"} {
|
||||
if { [file exists /tmp/RRFRaptor_status.tcl] } {
|
||||
source "/tmp/RRFRaptor_status.tcl"
|
||||
if {$RRFRaptor == "ON"} {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/active.wav
|
||||
} else {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/desactive.wav
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
# 203 Raptor quick scan sound
|
||||
if {$cmd == "203"} {
|
||||
if { [file exists /tmp/RRFRaptor_scan.tcl] } {
|
||||
source "/tmp/RRFRaptor_scan.tcl"
|
||||
if {$RRFRaptor == "None"} {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/qso_ko.wav
|
||||
} else {
|
||||
playSilence 1500
|
||||
playFile /opt/RRFRaptor/sounds/qso_ok.wav
|
||||
if {$RRFRaptor == "RRF"} {
|
||||
playFile /etc/spotnik/Srrf.wav
|
||||
} elseif {$RRFRaptor == "FON"} {
|
||||
playFile /etc/spotnik/Sfon.wav
|
||||
} elseif {$RRFRaptor == "TECHNIQUE"} {
|
||||
playFile /etc/spotnik/Stec.wav
|
||||
} elseif {$RRFRaptor == "INTERNATIONAL"} {
|
||||
playFile /etc/spotnik/Sint.wav
|
||||
} elseif {$RRFRaptor == "LOCAL"} {
|
||||
playFile /etc/spotnik/Sloc.wav
|
||||
} elseif {$RRFRaptor == "BAVARDAGE"} {
|
||||
playFile /etc/spotnik/Sbav.wav
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
```
|
||||
|
||||
>Attention, si vous modifiez également les codes __202__ et __203__ qui servent aux annonces vocales, vous devrez les modifiez également dans le script `/opt/RRFRaptor/RRFRaptor.sh`. Ce changement n'est pas recommandé.
|
||||
|
||||
# That's all
|
||||
|
||||
Bon trafic à tous, 88 & 73 de Armel F4HWN !
|
||||
Executable
+91
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
RRFRaptor
|
||||
Learn more about RRF on https://f5nlg.wordpress.com
|
||||
73 & 88 de F4HWN Armel
|
||||
'''
|
||||
|
||||
import settings as s
|
||||
import lib as l
|
||||
|
||||
import getopt
|
||||
import sys
|
||||
import time
|
||||
import datetime
|
||||
import os
|
||||
|
||||
def main(argv):
|
||||
|
||||
# Check et capture des arguments
|
||||
try:
|
||||
options, remainder = getopt.getopt(argv, '', ['help', 'version', 'sleep=', 'scan=', 'debug='])
|
||||
except getopt.GetoptError:
|
||||
l.usage()
|
||||
sys.exit(2)
|
||||
for opt, arg in options:
|
||||
if opt == '--help':
|
||||
l.usage()
|
||||
sys.exit()
|
||||
elif opt == '--version':
|
||||
print s.version
|
||||
sys.exit()
|
||||
elif opt in ('--sleep'):
|
||||
s.sleep = float(arg)
|
||||
elif opt in ('--scan'):
|
||||
if arg in ['True', 'true']:
|
||||
s.scan = True
|
||||
else:
|
||||
s.scan = False
|
||||
elif opt in ('--debug'):
|
||||
if arg in ['True', 'true']:
|
||||
s.debug = True
|
||||
else:
|
||||
s.debug = False
|
||||
|
||||
if s.scan is True: # Si scan simple
|
||||
l.where_is()
|
||||
while(True):
|
||||
if l.read_log() is True:
|
||||
file = open('/tmp/RRFRaptor_scan.tcl', 'w')
|
||||
file.write('set RRFRaptor "' + l.scan() + '"\n')
|
||||
file.close()
|
||||
sys.exit()
|
||||
|
||||
else: # Sinon, boucle principale
|
||||
while(True):
|
||||
# Lecture du salon courant
|
||||
l.where_is()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
if s.current_room != 'PARROT': # Si pas sur le perroquet
|
||||
# Lecture de l'activité
|
||||
l.read_log()
|
||||
|
||||
# Gestion de la temporisation
|
||||
s1 = s.room[s.current_room]['last']
|
||||
s2 = time.time()
|
||||
|
||||
if (s2 - s1) > s.sleep * 60: # Si la limite de temporisation atteinte, on scan
|
||||
if s.debug is True or s.scan is True: # Attention, on réutilise ici la variable s.scan mais ne pas la confondre avec l'option --scan
|
||||
s.scan = False
|
||||
print now.strftime('%H:%M:%S'), '-', 'Scan en cours...'
|
||||
l.qsy()
|
||||
else: # Sinon, on affiche éventuellement une trace
|
||||
s.scan = True # Attention, on réutilise ici la variable s.scan mais ne pas la confondre avec l'option --scan
|
||||
if s.debug is True:
|
||||
print now.strftime('%H:%M:%S'), '-', 'Standby sur ' + s.current_room + ' depuis ' + str(int(s2 - s1)) + ' secondes'
|
||||
else: # Sinon on ne fait rien sur le perroquet
|
||||
if s.debug is True:
|
||||
print now.strftime('%H:%M:%S'), '-', 'Perroquet...'
|
||||
|
||||
# On controle toutes les 2 secondes, c'est suffisant...
|
||||
time.sleep(5)
|
||||
sys.stdout.flush()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main(sys.argv[1:])
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH_SCRIPT='/opt/RRFRaptor/RRFRaptor.py'
|
||||
PATH_LOG='/tmp'
|
||||
PATH_PID='/tmp'
|
||||
|
||||
# Si pas d'argument, on gere tout seul
|
||||
if [ -z "$1" ]; then
|
||||
/usr/bin/pgrep -f 'python /opt/RRFRaptor/RRFRaptor.py'
|
||||
pid=$?
|
||||
if [ $pid != 1 ]; then
|
||||
set -- 'stop'
|
||||
else
|
||||
set -- 'start'
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting RRFRaptor"
|
||||
search="python ${PATH_SCRIPT}"
|
||||
pkill -f "${search}"
|
||||
nohup python $PATH_SCRIPT --sleep 1 --scan False --debug False > $PATH_LOG/RRFRaptor.log 2>&1 &
|
||||
echo 'set RRFRaptor "ON"' > /tmp/RRFRaptor_status.tcl
|
||||
echo "202#"> /tmp/dtmf_uhf
|
||||
echo "202#"> /tmp/dtmf_vhf
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping RRFRaptor"
|
||||
search="python ${PATH_SCRIPT}"
|
||||
pkill -f "${search}"
|
||||
echo 'set RRFRaptor "OFF"' > /tmp/RRFRaptor_status.tcl
|
||||
echo "202#"> /tmp/dtmf_uhf
|
||||
echo "202#"> /tmp/dtmf_vhf
|
||||
;;
|
||||
scan)
|
||||
echo "Simple Scan RRFRaptor"
|
||||
python $PATH_SCRIPT --scan True --debug False
|
||||
echo "203#"> /tmp/dtmf_uhf
|
||||
echo "203#"> /tmp/dtmf_vhf
|
||||
;;
|
||||
version)
|
||||
echo "Version RRFRaptor"
|
||||
python $PATH_SCRIPT --version
|
||||
;;
|
||||
esac
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
RRFRaptor
|
||||
Learn more about RRF on https://f5nlg.wordpress.com
|
||||
73 & 88 de F4HWN Armel
|
||||
'''
|
||||
|
||||
import settings as s
|
||||
import requests
|
||||
import os
|
||||
import time
|
||||
import datetime
|
||||
import json
|
||||
|
||||
# Usage
|
||||
def usage():
|
||||
print 'Usage: RRFRaptor.py [options ...]'
|
||||
print
|
||||
print '--help cet aide'
|
||||
print '--version numéro de version'
|
||||
print
|
||||
print 'Parametrages:'
|
||||
print
|
||||
print ' --sleep nombre Nombre de minutes avant scanning (3 minutes par défaut)'
|
||||
print ' --scan booléen Mode scan [True, False (défaut)]'
|
||||
print ' --debug booléen Mode debug [True, False (défaut)]'
|
||||
print
|
||||
print '88 & 73 from F4HWN Armel'
|
||||
|
||||
|
||||
# Lecture du flux Json
|
||||
def read_log():
|
||||
|
||||
# Requete HTTP vers le flux json du salon produit par le RRFTracker
|
||||
try:
|
||||
r = requests.get(s.room[s.current_room]['url'], verify=False, timeout=10)
|
||||
except requests.exceptions.ConnectionError as errc:
|
||||
print ('Error Connecting:', errc)
|
||||
except requests.exceptions.Timeout as errt:
|
||||
print ('Timeout Error:', errt)
|
||||
|
||||
# Controle de la validité du flux json
|
||||
rrf_data = ''
|
||||
try:
|
||||
rrf_data = r.json()
|
||||
except:
|
||||
pass
|
||||
|
||||
if rrf_data != '': # Si le flux est valide
|
||||
# On récupère le TOT du salon en court
|
||||
current_tot = rrf_data['abstract'][0]['TOT']
|
||||
s.room[s.current_room]['tot'] = current_tot
|
||||
|
||||
if current_tot != 0: # Si le TOT tourne encore
|
||||
s.room[s.current_room]['last'] = time.time()
|
||||
else: # Sinon, on commence à regarder ailleurs
|
||||
try:
|
||||
for data in rrf_data['elsewhere'][6]:
|
||||
if data in s.valid_room:
|
||||
tmp = rrf_data['elsewhere'][6][data]
|
||||
if tmp != 0:
|
||||
s.room[data]['tot'] = tmp
|
||||
else:
|
||||
s.room[data]['tot'] = 0
|
||||
except:
|
||||
if s.debug is True:
|
||||
print 'KeyError: \'elsewhere\''
|
||||
return False
|
||||
else: # Si le flux est invalide
|
||||
if s.debug is True:
|
||||
print 'Failed to read...'
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# Gestion des QSY
|
||||
def qsy(new_room = ''):
|
||||
cmd = ''
|
||||
old_room = s.current_room
|
||||
|
||||
if new_room != '': # Si une room est passée en argument
|
||||
cmd = '/etc/spotnik/restart.' + new_room[:3].lower()
|
||||
else: # Sinon
|
||||
for data in s.valid_room:
|
||||
if data != s.current_room:
|
||||
if s.room[data]['tot'] >= 3:
|
||||
s.current_room = data
|
||||
s.room[s.current_room]['last'] = time.time()
|
||||
cmd = '/etc/spotnik/restart.' + data[:3].lower()
|
||||
break
|
||||
|
||||
# Si une commande est en attente... on la joue !
|
||||
if cmd != '':
|
||||
now = datetime.datetime.now()
|
||||
print now.strftime('%H:%M:%S'), '- Execute', cmd, '(', old_room, ' -> ', s.current_room, ')'
|
||||
os.system(cmd)
|
||||
time.sleep(5) # Petite temporisation avant de killer le timersalon éventuel
|
||||
cmd = '/usr/bin/pkill -f timersalon'
|
||||
os.system(cmd)
|
||||
|
||||
return True
|
||||
|
||||
# Gestion du scan simple
|
||||
def scan():
|
||||
for data in s.valid_room:
|
||||
if s.room[data]['tot'] >= 3:
|
||||
return data
|
||||
break
|
||||
return 'None'
|
||||
|
||||
# Detection salon
|
||||
def where_is():
|
||||
detect_room = ''
|
||||
with open('/etc/spotnik/network', 'r') as content_file:
|
||||
content = content_file.read()
|
||||
content = content.strip()
|
||||
|
||||
if content == 'int':
|
||||
detect_room = 'INTERNATIONAL'
|
||||
elif content == 'bav':
|
||||
detect_room = 'BAVARDAGE'
|
||||
elif content == 'loc':
|
||||
detect_room = 'LOCAL'
|
||||
elif content == 'tec':
|
||||
detect_room = 'TECHNIQUE'
|
||||
elif content == 'default':
|
||||
detect_room = 'PARROT'
|
||||
else:
|
||||
detect_room = content.upper()
|
||||
|
||||
# QSY sur le salon RRF si perdu...
|
||||
if detect_room not in s.valid_room:
|
||||
s.current_room = 'RRF'
|
||||
qsy(s.current_room)
|
||||
s.room[s.current_room]['last'] = time.time()
|
||||
elif detect_room != s.current_room: # Si changement de salon...
|
||||
if s.scan is False:
|
||||
now = datetime.datetime.now()
|
||||
print now.strftime('%H:%M:%S'), '- QSY manuel', '(', s.current_room, ' -> ', detect_room, ')'
|
||||
s.current_room = detect_room
|
||||
s.room[s.current_room]['last'] = time.time()
|
||||
|
||||
return True
|
||||
|
||||
# Trace debugage
|
||||
def trace():
|
||||
for data in s.room:
|
||||
print data,
|
||||
if s.room[data]['tot'] == '':
|
||||
print s.room[data]['last']
|
||||
else:
|
||||
print s.room[data]['tot']
|
||||
print '-----'
|
||||
|
||||
return True
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
RRFRaptor
|
||||
Learn more about RRF on https://f5nlg.wordpress.com
|
||||
73 & 88 de F4HWN Armel
|
||||
'''
|
||||
|
||||
# Version
|
||||
|
||||
version = '1.3.3'
|
||||
|
||||
# Variables par defaut
|
||||
|
||||
sleep = 1 # Durée en minutes avant QSY
|
||||
scan = False # Mode scan
|
||||
debug = False # Mode debug
|
||||
current_room = '' # Salon courant
|
||||
|
||||
valid_room = ['PARROT', 'RRF', 'TECHNIQUE', 'LOCAL', 'BAVARDAGE', 'INTERNATIONAL'] # Ajoutez le 'FON' si vous le souhaitez
|
||||
|
||||
room = {
|
||||
'PARROT': {
|
||||
'url': '',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'RRF': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/RRF-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'TECHNIQUE': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/TECHNIQUE-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'INTERNATIONAL': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/INTERNATIONAL-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'LOCAL': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/LOCAL-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'BAVARDAGE': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/BAVARDAGE-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
},
|
||||
'FON': {
|
||||
'url': 'http://rrf.f5nlg.ovh:8080/RRFTracker/FON-today/rrf_tiny.json',
|
||||
'tot': 0,
|
||||
'last': ''
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user