first commit

This commit is contained in:
2022-08-24 08:18:01 +02:00
commit d3831d09c4
1124 changed files with 6738 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/python2
#
# This is a simple serial programmer for the 818 VHF/UHF modules.
# by w0anm
# This code was created from examples on the web.
#
# $Id: 818-prog 12 2014-12-27 18:27:47Z w0anm $
import time
import serial
# configure the serial connections (the parameters differs on the device
# you are connecting to)
ser = serial.Serial(
port='/dev/ttyS2',
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
# ser.open()
ser.isOpen()
print '\r\n\n'
print 'Programing DRA818x and SA818x Module \r\n\n'
print 'Device name:'
print ' ' + ser.portstr # check which port was really used
key=1
while key == 1:
print '------------------------------------------------------'
Spacing=raw_input('Enter Channel Spacing (0 or 1): ')
FreqTx=raw_input('Enter Tx Frequency (xxx.xxxx): ')
FreqRx=raw_input('Enter Rx Frequency (xxx.xxxx): ')
tx_ctcss=raw_input('Enter Tx ctcss Code Value (xxxx): ')
rx_ctcss=raw_input('Enter Rx ctcss Code Value (xxxx): ')
squelch=raw_input ('Enter Squelch Value (1-9): ')
Volume=raw_input('Enter Volume (0-8): ')
PreEmphasis=raw_input('Enable Pre/De-Emphasis (y/[n]): ')
if PreEmphasis == "":
PreEmphasis="n"
HighPass=raw_input('Enable High Pass Filter (y/[n]): ')
if HighPass == "":
HighPass="n"
LowPass=raw_input('Enable Low Pass Filter (y/[n]): ')
if LowPass == "":
LowPass="n"
#
print ''
print 'Verify:'
print '------------------------------------------------------'
print ' Channel Spacing: ' + Spacing + ' '
print ' Tx Frequency: ' + FreqTx + ' '
print ' Rx Frequency: ' + FreqRx + ' '
print ' Tx CTCSS code: ' + tx_ctcss + ' '
print ' Rx CTCSS code: ' + rx_ctcss + ' '
print ' Squelch Value: ' + squelch + ' '
print ' Volume Value: ' + Volume + ' '
print ' PreEmphasis Enabled: ' + PreEmphasis + ' '
print ' High Pass Enabled: ' + HighPass + ' '
print ' Low Pass Enabled: ' + LowPass + ' '
print '------------------------------------------------------'
Answer=""
Answer=raw_input(' Is this correct ([y]/n, or a to abort) ?')
if Answer == "":
Answer = "y"
if Answer == "y":
break
if Answer == "a":
exit()
# print 'Enter your commands below.\r\nInsert "exit" to leave the application.'
# Example of the command:
# ser.write("AT+DMOSETGROUP=1,446.0500,446.0500,0020,4,0020\r\n")
# Set Freq/Group
print 'Sending Freq Information...'
ser.write("AT+DMOSETGROUP=" + Spacing + "," + FreqTx + "," + FreqRx + "," + tx_ctcss + "," + squelch + "," + rx_ctcss + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETGROUP:1
if response == '+DMOSETGROUP:1':
print " Error, invalid information (" + response + "). Check input format.."
print " Command Sent:"
print " AT+DMOSETGROUP=1," + FreqTx + "," + FreqRx + "," + tx_ctcss + "," + squelch + "," + rx_ctcss + "\r\n"
exit()
# Set Volume
print "Setting Volume - " + Volume + " "
ser.write("AT+DMOSETVOLUME=" + Volume + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETVOLUME:1
if response == '+DMOSETVOLUME:1':
print " Error, invalid information (" + response + ")..."
print " Command Sent:"
print " AT+DMOSETVOLUME=" + Volume + "\r\n"
exit()
# Set Filters:
# convert filters values, 0 is enable, and 1 is disable
if PreEmphasis == "n":
PreEmpFilter='1'
else:
PreEmpFilter='0'
if HighPass == "n":
HPass='1'
else:
HPass='0'
if LowPass == "n":
LPass='1'
else:
LPass='0'
print 'Setting Filters'
ser.write("AT+SETFILTER=" + PreEmpFilter + "," + HPass + "," + LPass + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETFILTER:1
if response == '+DMOSETFILTER:1':
print " Error, invalid information (" + response + ")..."
print " Command Sent:"
print " AT+SETFILTER=" + PreEmpFilter + "," + HPass + "," + LPass + "\r\n"
exit()
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/python2
# This is a simple serial programmer for the 818 VHF/UHF modules.
# Supported command line interfaces, non-interactive
# by w0anm
# This code was created from examples on the web.
#
# $Id: 818cli-prog 12 2014-12-27 18:27:47Z w0anm $
import sys, getopt
import time, serial
def main(argv):
mode = '0' # 0 for NFM, 1 for FM
group = '446.1687,446.1687,0000,1,0000'
volume = '4'
filter = '0,0,0'
device = '/dev/ttyAMA0'
try:
opts, args = getopt.getopt(argv,"hd:m:g:v:f")
except getopt.GetoptError:
print '\n818cli-prog [-d <device>] [-m <mode> -g <group> -v <volume> -f <filter>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print '\n818cli-prog [-d <device>] [-m <mode>] -g <group> [-v <volume>] [-f <filter>]'
print ' device = serial device, default /dev/ttyUSB0'
print ' e.g., -d /dev/ttyUSB0'
print ' mode = 0 - 12.5 Khz Ch Space, 1 - 25 Khz Ch Space, default 0'
print ' e.g., -m 0'
print ' group = <RxFreq>,<TxFreq>,<Rxct>,<Squelch>,<Txct>'
print ' <RxFreq> and <TxFreq> format: xxx.xxxx '
print ' <Rxct> and <Txct> format:'
print ' xxxx (tones) '
print ' xxx[N,I] (DTCS) '
print ' <Squelch> value is 0-8'
print ' e.g., -g 446.0500,446.0500,754N,6,754N '
print ' volume = Value is 0-8, default 4'
print ' e.g., -v 4 '
print ' filter = <pre-emphasis>,<low-pass>,<high-pass>'
print ' default is all filters disable (1,1,1)'
print ' to enable a filter, use 0 for the value '
print ' to disable a filter, use 1 for the value'
print ' e.g., -f 0,0,0 (enables all filters) '
print ' '
print 'Command line example:'
print ' 818cli-prog -d /dev/ttyUSB0 -m 0 -g 446.0500,446.0500,754N,6,754N -v 4 -f 0,0,0 '
sys.exit()
elif opt in ("-d"):
device = arg
elif opt in ("-g"):
group = arg
elif opt in ("-m"):
mode = arg
elif opt in ("-v"):
volume = arg
elif opt in ("-a"):
filter = arg
############################################################################
# configure the serial connections (the parameters differs on the device
# you are connecting to)
ser = serial.Serial(
port=device,
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
# ser.open()
ser.isOpen()
print '\r\n\n'
print 'Programing DRA818x and SA818x Module \r\n\n'
print 'Device name:'
print ' ' + ser.portstr # check which port was really used
# Set Connexion
print 'Sending Connexion ...'
ser.write("AT+DMOCONNECT\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
print (response)
# Set Freq/Group
print 'Sending Freq Information...'
ser.write("AT+DMOSETGROUP=" + mode + "," + group + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETGROUP:1
if response == '+DMOSETGROUP:1':
print " Error, invalid information (" + response + "). Check input format.."
print " Command Sent:"
print " AT+DMOSETGROUP=" + mode + "," + group + "\r\n"
print ' group usage:'
print ' <mode> = Channel Space (0 or 1)'
print ' <group> = RxFreq,TxFreq,Rxct,Squelch,Txct'
print ' Using this format: '
print ' xxx.xxxx,yyy.yyyy,rrrr,s,tttt\n'
print ' For example:'
print ' -g 446.0500,446.0500,754N,6,754N '
print ' RxFreq and TxFreq xxx.xxxx '
print ' Rxct and Txct format xxxx (tones) '
print ' or xxx[N,I] (DTCS) \n '
print ' Squelch value range: 0-8'
exit()
# Set Volume
print "Setting Volume - " + volume + " "
ser.write("AT+DMOSETVOLUME=" + volume + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETVOLUME:1
if response == '+DMOSETVOLUME:1':
print " Error, invalid information (" + response + ")..."
print " Command Sent:"
print " AT+DMOSETVOLUME=" + volume + "\r\n"
exit()
print 'Setting Filters'
ser.write("AT+SETFILTER=" + filter + "\r\n")
time.sleep(1.00)
#evaluate response
raw_serial = ser.readline()
response = raw_serial[:-2]
# Bad response --> +DMOSETFILTER:1
if response == '+DMOSETFILTER:1':
print " Error, invalid information (" + response + ")..."
print " Command Sent:"
print " AT+SETFILTER=" + filter + "\r\n"
exit()
print 'Setup Complete'
if __name__ == "__main__":
main(sys.argv[1:])
+102
View File
@@ -0,0 +1,102 @@
le programme 818cli-prog , programme la radio sur 432.975 MHZ , CTCSS 71.9Hz , volume a 4 , tous filtres activés . c'est la configuration de base des spotnik Delta.
This program is written in python2 and is configured to use a FTDI USB to
Serial Adapter. I have tested this on Linux systems and the on BeagleBone
Black computer.
For the BealeBone Black, I've included a simple install script that will
install any package dependencies.
There are no variable format checks at this time. When prompted for values,
pay close attention to the format of the data. For example:
Frequencies should be entered as XXX.YYYY using the full four digits.
CTSS/DCS values should be entered with four digits, 0022 or 0754N. See
below for more details.
Standard CTCSS Tones:
Motorola RELM | Motorola RELM
Tone Code Code | Tone Code Code
================================================================
None None 000 | 167.9 6Z 33
67.0 XZ 001 | 173.8 6A 34
71.9 XA 002 | 179.9 6B 35
74.4 WA 003 | 186.2 7Z 36
77.0 XB 004 | 192.8 7A 37
79.7 WB 005 | 203.5 M1 38
82.5 YZ 006 | 210.7 M2 none
85.4 YA 007 | 218.1 M3 none
88.5 YB 008 | 225.7 M4 none
91.5 ZZ 009 | 233.6 none none
94.8 ZA 010 | 241.8 none none
97.4 ZB 011 | 250.3 none none
100.0 1Z 012 | 69.4 WZ none
103.5 1A 013 | 159.8 none none
107.2 1B 014 | 165.5 none none
110.9 2Z 015 | 171.3 none none
114.8 2A 016 | 177.3 none none
118.8 2B 017 | 183.5 none none
123.0 3Z 018 | 189.9 none none
127.3 3A 019 | 196.6 none none
131.8 3B 020 | 199.5 none none
136.5 4Z 021 | 206.5 8Z none
141.3 4A 022 | 229.1 9Z none
146.2 4B 023 | 254.1 0Z none
151.4 5Z 024 | 150.0 none none
156.7 5A 025 |
162.2 5B 026 |
The CTCSS tones should be entered using all for digits, for example CTCCS
tone 181.8, should be entered as 0020.
DCS Codes:
CDCSS or Digital Code Squelch (DCS) is a further development of the continuous
tone-coded squelch system or CTCSS that uses a slow-speed, binary data
stream passed as sub-audible data along with the transmission. Motorola
calls this Digital Private Line or DPL. It consists of a 23-bit telegram
sent repeatedly on the channel at 134 bits per second along with the voice
transmission. This allows for over 100 possible fleet codes to be used.
This gives it an advantage over the CTCSS tones in that there are more
possible codes to use; however, it does use more bandwidth and can be
affected by voice tones below 300 Hz if not properly filtered by the
radio circuitry. Below is a chart of the DCS codes:
6 50 125 174 255 343 445 526 703
7 51 131 205 261 346 446 532 712
15 53 132 212 263 351 452 546 723
17 54 134 214 265 356 454 565 731
21 65 141 223 266 364 455 606 732
23 71 143 225 271 365 462 612 734
25 72 145 226 274 371 464 624 743
26 73 152 243 306 411 465 627 754
31 74 155 244 311 412 466 631
32 114 156 245 315 413 503 632
36 115 162 246 325 423 506 654
43 116 165 251 331 431 516 662
47 122 172 252 332 432 523 664
The format needs to be full three digets plus an "N". For example, DCS code 7
should be entered as : 007N
Inverted Codes
The format for inverted codes is the same as DCS codes except instead of an "N"
you change it to "I". For example, DCS code 7 inverted, would be entered as:
007I.
$Id: README.txt 3 2014-12-03 01:04:43Z w0anm $
+7
View File
@@ -0,0 +1,7 @@
build
*.egg-info
*.pyc
setuptools-*
*.so
dist
@@ -0,0 +1,217 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
import re
from . import common
from . import Beaglebone_Black_Driver as driver
# Define mapping of pin names to GPIO base and number.
# Adapted from Adafruit_BBIO code Beaglebone Black system reference.
pin_to_gpio = {
"P9_11": (0,30),
"P9_12": (1,28),
"P9_13": (0,31),
"P9_14": (1,18),
"P9_15": (1,16),
"P9_16": (1,19),
"P9_17": (0,5),
"P9_18": (0,4),
"P9_19": (0,13),
"P9_20": (0,12),
"P9_21": (0,3),
"P9_22": (0,2),
"P9_23": (1,17),
"P9_24": (0,15),
"P9_25": (3,21),
"P9_26": (0,14),
"P9_27": (3,19),
"P9_28": (3,17),
"P9_29": (3,15),
"P9_30": (3,16),
"P9_31": (3,14),
"P9_41": (0,20),
"P9_42": (0,7),
"UART4_RXD": (0,30),
"UART4_TXD": (0,31),
"EHRPWM1A": (1,18),
"EHRPWM1B": (1,19),
"I2C1_SCL": (0,5),
"I2C1_SDA": (0,4),
"I2C2_SCL": (0,13),
"I2C2_SDA": (0,12),
"UART2_TXD": (0,3),
"UART2_RXD": (0,2),
"UART1_TXD": (0,15),
"UART1_RXD": (0,14),
"SPI1_CS0": (3,17),
"SPI1_D0": (3,15),
"SPI1_D1": (3,16),
"SPI1_SCLK": (3,14),
"CLKOUT2": (0,20),
"30": (0,30),
"60": (1,28),
"31": (0,31),
"50": (1,18),
"48": (1,16),
"51": (1,19),
"5": (0,5),
"4": (0,4),
"13": (0,13),
"12": (0,12),
"3": (0,3),
"2": (0,2),
"49": (1,17),
"15": (0,15),
"117": (3,21),
"14": (0,14),
"115": (3,19),
"113": (3,17),
"111": (3,15),
"112": (3,16),
"110": (3,14),
"20": (0,20),
"7": (0,7),
"P8_3": (1,6),
"P8_4": (1,7),
"P8_5": (1,2),
"P8_6": (1,3),
"P8_7": (2,2),
"P8_8": (2,3),
"P8_9": (2,5),
"P8_10": (2,4),
"P8_11": (1,13),
"P8_12": (1,12),
"P8_13": (0,23),
"P8_14": (0,26),
"P8_15": (1,15),
"P8_16": (1,14),
"P8_17": (0,27),
"P8_18": (2,1),
"P8_19": (0,22),
"P8_20": (1,31),
"P8_21": (1,30),
"P8_22": (1,5),
"P8_23": (1,4),
"P8_24": (1,1),
"P8_25": (1,0),
"P8_26": (1,29),
"P8_27": (2,22),
"P8_28": (2,24),
"P8_29": (2,23),
"P8_30": (2,25),
"P8_31": (0,10),
"P8_32": (0,11),
"P8_33": (0,9),
"P8_34": (2,17),
"P8_35": (0,8),
"P8_36": (2,16),
"P8_37": (2,14),
"P8_38": (2,15),
"P8_39": (2,12),
"P8_40": (2,13),
"P8_41": (2,10),
"P8_42": (2,11),
"P8_43": (2,8),
"P8_44": (2,9),
"P8_45": (2,6),
"P8_46": (2,7),
"TIMER4": (2,2),
"TIMER7": (2,3),
"TIMER5": (2,5),
"TIMER6": (2,4),
"EHRPWM2B": (0,23),
"EHRPWM2A": (0,22),
"UART5_CTSN": (0,10),
"UART5_RTSN": (0,11),
"UART4_RTSN": (0,9),
"UART3_RTSN": (2,17),
"UART4_CTSN": (0,8),
"UART3_CTSN": (2,16),
"UART5_TXD": (2,14),
"UART5_RXD": (2,15),
"38": (1,6),
"39": (1,7),
"34": (1,2),
"35": (1,3),
"66": (2,2),
"67": (2,3),
"69": (2,5),
"68": (2,4),
"45": (1,13),
"44": (1,12),
"23": (0,23),
"26": (0,26),
"47": (1,15),
"46": (1,14),
"27": (0,27),
"65": (2,1),
"22": (0,22),
"63": (1,31),
"62": (1,30),
"37": (1,5),
"36": (1,4),
"33": (1,1),
"32": (1,0),
"61": (1,29),
"86": (2,22),
"88": (2,24),
"87": (2,23),
"89": (2,25),
"10": (0,10),
"11": (0,11),
"9": (0,9),
"81": (2,17),
"8": (0,8),
"80": (2,16),
"78": (2,14),
"79": (2,15),
"76": (2,12),
"77": (2,13),
"74": (2,10),
"75": (2,11),
"72": (2,8),
"73": (2,9),
"70": (2,6),
"71": (2,7)
}
def read(sensor, pin):
# Validate GPIO and map it to GPIO base and number.
gpio = pin_to_gpio.get(str(pin).upper(), None)
if gpio is None:
# Couldn't find in mapping, check if pin looks like GPIO<base>_<number>
match = re.match('GPIO([0123])_(\d+)', pin, re.IGNORECASE)
if match is not None:
gpio = (int(match.group(1)), int(match.group(2)))
if gpio is None or gpio[0] < 0 or gpio[0] > 3 or gpio[1] < 0 or gpio[1] > 31:
raise ValueError('Pin must be a valid GPIO identifier like P9_12 or GPIO1_28.')
# Get a reading from C driver code.
result, humidity, temp = driver.read(sensor, gpio[0], gpio[1])
if result in common.TRANSIENT_ERRORS:
# Signal no result could be obtained, but the caller can retry.
return (None, None)
elif result == common.DHT_ERROR_GPIO:
raise RuntimeError('Error accessing GPIO. Make sure program is run as root with sudo!')
elif result != common.DHT_SUCCESS:
# Some kind of error occured.
raise RuntimeError('Error calling DHT test driver read: {0}'.format(result))
return (humidity, temp)
+40
View File
@@ -0,0 +1,40 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
from . import common
from . import Raspberry_Pi_Driver as driver
def read(sensor, pin):
# Validate pin is a valid GPIO.
if pin is None or int(pin) < 0 or int(pin) > 31:
raise ValueError('Pin must be a valid GPIO number 0 to 31.')
# Get a reading from C driver code.
result, humidity, temp = driver.read(sensor, int(pin))
if result in common.TRANSIENT_ERRORS:
# Signal no result could be obtained, but the caller can retry.
return (None, None)
elif result == common.DHT_ERROR_GPIO:
raise RuntimeError(
'Error accessing GPIO. If `/dev/gpiomem` does not exist '
'run this program as root or sudo.')
elif result != common.DHT_SUCCESS:
# Some kind of error occured.
raise RuntimeError('Error calling DHT test driver read: {0}'.format(result))
return (humidity, temp)
+38
View File
@@ -0,0 +1,38 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
from . import common
from . import Raspberry_Pi_2_Driver as driver
def read(sensor, pin):
# Validate pin is a valid GPIO.
if pin is None or int(pin) < 0 or int(pin) > 31:
raise ValueError('Pin must be a valid GPIO number 0 to 31.')
# Get a reading from C driver code.
result, humidity, temp = driver.read(sensor, int(pin))
if result in common.TRANSIENT_ERRORS:
# Signal no result could be obtained, but the caller can retry.
return (None, None)
elif result == common.DHT_ERROR_GPIO:
raise RuntimeError('Error accessing GPIO.')
elif result != common.DHT_SUCCESS:
# Some kind of error occured.
raise RuntimeError('Error calling DHT test driver read: {0}'.format(result))
return (humidity, temp)
+33
View File
@@ -0,0 +1,33 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
from . import common
from . import Test_Driver as driver
def read(sensor, pin):
# Get a reading from C driver code.
result, humidity, temp = driver.read(sensor, pin)
if result in common.TRANSIENT_ERRORS:
# Signal no result could be obtained, but the caller can retry.
return (None, None)
elif result != common.DHT_SUCCESS:
# Some kind of error occured.
raise RuntimeError('Error calling DHT test driver read: {0}'.format(result))
return (humidity, temp)
+21
View File
@@ -0,0 +1,21 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
from .common import DHT11, DHT22, AM2302, read, read_retry
+98
View File
@@ -0,0 +1,98 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
import time
from . import platform_detect
# Define error constants.
DHT_SUCCESS = 0
DHT_ERROR_TIMEOUT = -1
DHT_ERROR_CHECKSUM = -2
DHT_ERROR_ARGUMENT = -3
DHT_ERROR_GPIO = -4
TRANSIENT_ERRORS = [DHT_ERROR_CHECKSUM, DHT_ERROR_TIMEOUT]
# Define sensor type constants.
DHT11 = 11
DHT22 = 22
AM2302 = 22
SENSORS = [DHT11, DHT22, AM2302]
def get_platform():
"""Return a DHT platform interface for the currently detected platform."""
plat = platform_detect.platform_detect()
if plat == platform_detect.RASPBERRY_PI:
# Check for version 1 or 2 of the pi.
version = platform_detect.pi_version()
if version == 1:
from . import Raspberry_Pi
return Raspberry_Pi
elif version == 2:
from . import Raspberry_Pi_2
return Raspberry_Pi_2
elif version == 3:
"""Use Pi 2 driver even though running on Pi 3"""
from . import Raspberry_Pi_2
return Raspberry_Pi_2
else:
raise RuntimeError('No driver for detected Raspberry Pi version available!')
elif plat == platform_detect.BEAGLEBONE_BLACK:
from . import Beaglebone_Black
return Beaglebone_Black
else:
raise RuntimeError('Unknown platform.')
def read(sensor, pin, platform=None):
"""Read DHT sensor of specified sensor type (DHT11, DHT22, or AM2302) on
specified pin and return a tuple of humidity (as a floating point value
in percent) and temperature (as a floating point value in Celsius). Note that
because the sensor requires strict timing to read and Linux is not a real
time OS, a result is not guaranteed to be returned! In some cases this will
return the tuple (None, None) which indicates the function should be retried.
Also note the DHT sensor cannot be read faster than about once every 2 seconds.
Platform is an optional parameter which allows you to override the detected
platform interface--ignore this parameter unless you receive unknown platform
errors and want to override the detection.
"""
if sensor not in SENSORS:
raise ValueError('Expected DHT11, DHT22, or AM2302 sensor value.')
if platform is None:
platform = get_platform()
return platform.read(sensor, pin)
def read_retry(sensor, pin, retries=15, delay_seconds=2, platform=None):
"""Read DHT sensor of specified sensor type (DHT11, DHT22, or AM2302) on
specified pin and return a tuple of humidity (as a floating point value
in percent) and temperature (as a floating point value in Celsius).
Unlike the read function, this read_retry function will attempt to read
multiple times (up to the specified max retries) until a good reading can be
found. If a good reading cannot be found after the amount of retries, a tuple
of (None, None) is returned. The delay between retries is by default 2
seconds, but can be overridden.
"""
for i in range(retries):
humidity, temperature = read(sensor, pin, platform)
if humidity is not None and temperature is not None:
return (humidity, temperature)
time.sleep(delay_seconds)
return (None, None)
+114
View File
@@ -0,0 +1,114 @@
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
# This is a direct copy of what's in the Adafruit Python GPIO library:
# https://raw.githubusercontent.com/adafruit/Adafruit_Python_GPIO/master/Adafruit_GPIO/Platform.py
# TODO: Add dependency on Adafruit Python GPIO and use its platform detect
# functions.
import platform
import re
# Platform identification constants.
UNKNOWN = 0
RASPBERRY_PI = 1
BEAGLEBONE_BLACK = 2
def platform_detect():
"""Detect if running on the Raspberry Pi or Beaglebone Black and return the
platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN."""
# Handle Raspberry Pi
pi = pi_version()
if pi is not None:
return RASPBERRY_PI
# Handle Beaglebone Black
# TODO: Check the Beaglebone Black /proc/cpuinfo value instead of reading
# the platform.
plat = platform.platform()
if plat.lower().find('armv7l-with-debian') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-ubuntu') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-glibc2.4') > -1:
return BEAGLEBONE_BLACK
elif plat.lower().find('armv7l-with-arch') > -1:
return BEAGLEBONE_BLACK
# Couldn't figure out the platform, just return unknown.
return UNKNOWN
def pi_revision():
"""Detect the revision number of a Raspberry Pi, useful for changing
functionality like default I2C bus based on revision."""
# Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History
with open('/proc/cpuinfo', 'r') as infile:
for line in infile:
# Match a line of the form "Revision : 0002" while ignoring extra
# info in front of the revsion (like 1000 when the Pi was over-volted).
match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE)
if match and match.group(1) in ['0000', '0002', '0003']:
# Return revision 1 if revision ends with 0000, 0002 or 0003.
return 1
elif match:
# Assume revision 2 if revision ends with any other 4 chars.
return 2
# Couldn't find the revision, throw an exception.
raise RuntimeError('Could not determine Raspberry Pi revision.')
def pi_version():
"""Detect the version of the Raspberry Pi. Returns either 1, 2, 3 or
None depending on if it's a Raspberry Pi 1 (model A, B, A+, B+),
Raspberry Pi 2 (model B+), Raspberry Pi 3,Raspberry Pi 3 (model B+), Raspberry Pi 4
or not a Raspberry Pi.
"""
# Check /proc/cpuinfo for the Hardware field value.
# 2708 is pi 1
# 2709 is pi 2
# 2835 is pi 3 or pi 4
# 2837 is pi 3b+
# Anything else is not a pi.
with open('/proc/cpuinfo', 'r') as infile:
cpuinfo = infile.read()
# Match a line like 'Hardware : BCM2709'
match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo,
flags=re.MULTILINE | re.IGNORECASE)
if not match:
# Couldn't find the hardware, assume it isn't a pi.
return None
if match.group(1) == 'BCM2708':
# Pi 1
return 1
elif match.group(1) == 'BCM2709':
# Pi 2
return 2
elif match.group(1) == 'BCM2835':
# Pi 3 or Pi 4
return 3
elif match.group(1) == 'BCM2837':
# Pi 3b+
return 3
else:
# Something else, not a pi.
return None
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Adafruit Industries
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.
+2
View File
@@ -0,0 +1,2 @@
include README.md
recursive-include source *
+104
View File
@@ -0,0 +1,104 @@
*DEPRECATED LIBRARY* Adafruit Python DHT Sensor Library
=======================
his library has been deprecated! We are leaving this up for historical and research purposes but archiving the repository.
We are now only supporting the use of our CircuitPython libraries for use with Python.
Check out this guide for info on using DHT sensors with the CircuitPython library: https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging/python-setup
---------------------------------------
Python library to read the DHT series of humidity and temperature sensors on a
Raspberry Pi or Beaglebone Black.
Designed specifically to work with the Adafruit DHT series sensors ---->
https://www.adafruit.com/products/385
Currently the library is tested with Python 2.6, 2.7, 3.3 and 3.4. It should
work with Python greater than 3.4, too.
Installing
----------
### Dependencies
For all platforms (Raspberry Pi and Beaglebone Black) make sure your system is
able to compile and download Python extensions with **pip**:
On Raspbian or Beaglebone Black's Debian/Ubuntu image you can ensure your
system is ready by running one or two of the following sets of commands:
Python 2:
````sh
sudo apt-get update
sudo apt-get install python-pip
sudo python -m pip install --upgrade pip setuptools wheel
````
Python 3:
````sh
sudo apt-get update
sudo apt-get install python3-pip
sudo python3 -m pip install --upgrade pip setuptools wheel
````
### Install with pip
Use `pip` to install from PyPI.
Python 2:
```sh
sudo pip install Adafruit_DHT
```
Python 3:
```sh
sudo pip3 install Adafruit_DHT
```
### Compile and install from the repository
First download the library source code from the [GitHub releases
page](https://github.com/adafruit/Adafruit_Python_DHT/releases), unzipping the
archive, and execute:
Python 2:
```sh
cd Adafruit_Python_DHT
sudo python setup.py install
```
Python 3:
```sh
cd Adafruit_Python_DHT
sudo python3 setup.py install
```
You may also git clone the repository if you want to test an unreleased
version:
```sh
git clone https://github.com/adafruit/Adafruit_Python_DHT.git
```
Usage
-----
See example of usage in the examples folder.
Author
------
Adafruit invests time and resources providing this open source code, please
support Adafruit and open-source hardware by purchasing products from Adafruit!
Written by Tony DiCola for Adafruit Industries.
MIT license, all text above must be included in any redistribution
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/python
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
import sys
import Adafruit_DHT
# Parse command line parameters.
sensor_args = { '11': Adafruit_DHT.DHT11,
'22': Adafruit_DHT.DHT22,
'2302': Adafruit_DHT.AM2302 }
if len(sys.argv) == 3 and sys.argv[1] in sensor_args:
sensor = sensor_args[sys.argv[1]]
pin = sys.argv[2]
else:
print('Usage: sudo ./Adafruit_DHT.py [11|22|2302] <GPIO pin number>')
print('Example: sudo ./Adafruit_DHT.py 2302 4 - Read from an AM2302 connected to GPIO pin #4')
sys.exit(1)
# Try to grab a sensor reading. Use the read_retry method which will retry up
# to 15 times to get a sensor reading (waiting 2 seconds between each retry).
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
# Un-comment the line below to convert the temperature to Fahrenheit.
# temperature = temperature * 9/5.0 + 32
# Note that sometimes you won't get a reading and
# the results will be null (because Linux can't
# guarantee the timing of calls to read the sensor).
# If this happens try again!
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}* Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
sys.exit(1)
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/python
# Google Spreadsheet DHT Sensor Data-logging Example
# Depends on the 'gspread' and 'oauth2client' package being installed. If you
# have pip installed execute:
# sudo pip install gspread oauth2client
# Also it's _very important_ on the Raspberry Pi to install the python-openssl
# package because the version of Python is a bit old and can fail with Google's
# new OAuth2 based authentication. Run the following command to install the
# the package:
# sudo apt-get update
# sudo apt-get install python-openssl
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
import json
import sys
import time
import datetime
import Adafruit_DHT
import gspread
from oauth2client.service_account import ServiceAccountCredentials
# Type of sensor, can be Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302.
DHT_TYPE = Adafruit_DHT.DHT22
# Example of sensor connected to Raspberry Pi pin 23
DHT_PIN = 23
# Example of sensor connected to Beaglebone Black pin P8_11
#DHT_PIN = 'P8_11'
# Google Docs OAuth credential JSON file. Note that the process for authenticating
# with Google docs has changed as of ~April 2015. You _must_ use OAuth2 to log
# in and authenticate with the gspread library. Unfortunately this process is much
# more complicated than the old process. You _must_ carefully follow the steps on
# this page to create a new OAuth service in your Google developer console:
# http://gspread.readthedocs.org/en/latest/oauth2.html
#
# Once you've followed the steps above you should have downloaded a .json file with
# your OAuth2 credentials. This file has a name like SpreadsheetData-<gibberish>.json.
# Place that file in the same directory as this python script.
#
# Now one last _very important_ step before updating the spreadsheet will work.
# Go to your spreadsheet in Google Spreadsheet and share it to the email address
# inside the 'client_email' setting in the SpreadsheetData-*.json file. For example
# if the client_email setting inside the .json file has an email address like:
# 149345334675-md0qff5f0kib41meu20f7d1habos3qcu@developer.gserviceaccount.com
# Then use the File -> Share... command in the spreadsheet to share it with read
# and write acess to the email address above. If you don't do this step then the
# updates to the sheet will fail!
GDOCS_OAUTH_JSON = 'your SpreadsheetData-*.json file name'
# Google Docs spreadsheet name.
GDOCS_SPREADSHEET_NAME = 'your google docs spreadsheet name'
# How long to wait (in seconds) between measurements.
FREQUENCY_SECONDS = 30
def login_open_sheet(oauth_key_file, spreadsheet):
"""Connect to Google Docs spreadsheet and return the first worksheet."""
try:
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name(oauth_key_file, scope)
gc = gspread.authorize(credentials)
worksheet = gc.open(spreadsheet).sheet1
return worksheet
except Exception as ex:
print('Unable to login and get spreadsheet. Check OAuth credentials, spreadsheet name, and make sure spreadsheet is shared to the client_email address in the OAuth .json file!')
print('Google sheet login failed with error:', ex)
sys.exit(1)
print('Logging sensor measurements to {0} every {1} seconds.'.format(GDOCS_SPREADSHEET_NAME, FREQUENCY_SECONDS))
print('Press Ctrl-C to quit.')
worksheet = None
while True:
# Login if necessary.
if worksheet is None:
worksheet = login_open_sheet(GDOCS_OAUTH_JSON, GDOCS_SPREADSHEET_NAME)
# Attempt to get sensor reading.
humidity, temp = Adafruit_DHT.read(DHT_TYPE, DHT_PIN)
# Skip to the next reading if a valid measurement couldn't be taken.
# This might happen if the CPU is under a lot of load and the sensor
# can't be reliably read (timing is critical to read the sensor).
if humidity is None or temp is None:
time.sleep(2)
continue
print('Temperature: {0:0.1f} C'.format(temp))
print('Humidity: {0:0.1f} %'.format(humidity))
# Append the data in the spreadsheet, including a timestamp
try:
worksheet.append_row((datetime.datetime.now().isoformat(), temp, humidity))
except:
# Error appending data, most likely because credentials are stale.
# Null out the worksheet so a login is performed at the top of the loop.
print('Append error, logging in again')
worksheet = None
time.sleep(FREQUENCY_SECONDS)
continue
# Wait 30 seconds before continuing
print('Wrote a row to {0}'.format(GDOCS_SPREADSHEET_NAME))
time.sleep(FREQUENCY_SECONDS)
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/python
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola
# 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.
import Adafruit_DHT
# Sensor should be set to Adafruit_DHT.DHT11,
# Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302.
sensor = Adafruit_DHT.DHT22
# Example using a Beaglebone Black with DHT sensor
# connected to pin P8_11.
pin = 'P8_11'
# Example using a Raspberry Pi with DHT sensor
# connected to GPIO23.
#pin = 23
# Try to grab a sensor reading. Use the read_retry method which will retry up
# to 15 times to get a sensor reading (waiting 2 seconds between each retry).
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
# Note that sometimes you won't get a reading and
# the results will be null (because Linux can't
# guarantee the timing of calls to read the sensor).
# If this happens try again!
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(temperature, humidity))
else:
print('Failed to get reading. Try again!')
+110
View File
@@ -0,0 +1,110 @@
from setuptools import setup, find_packages, Extension
import os
import sys
import Adafruit_DHT.platform_detect as platform_detect
BINARY_COMMANDS = [
'build_ext',
'build_clib',
'bdist',
'bdist_dumb',
'bdist_rpm',
'bdist_wininst',
'bdist_wheel',
'install'
]
def is_binary_install():
do_binary = [command for command in BINARY_COMMANDS if command in sys.argv]
return len(do_binary) > 0
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
# Check if an explicit platform was chosen with a command line parameter.
# Kind of hacky to manipulate the argument list before calling setup, but it's
# the best simple option for adding optional config to the setup.
platform = platform_detect.UNKNOWN
pi_version = None
if '--force-pi' in sys.argv:
platform = platform_detect.RASPBERRY_PI
pi_version = 1
sys.argv.remove('--force-pi')
elif '--force-pi2' in sys.argv:
platform = platform_detect.RASPBERRY_PI
pi_version = 2
sys.argv.remove('--force-pi2')
elif '--force-bbb' in sys.argv:
platform = platform_detect.BEAGLEBONE_BLACK
sys.argv.remove('--force-bbb')
elif '--force-test' in sys.argv:
platform = 'TEST'
sys.argv.remove('--force-test')
else:
# No explicit platform chosen, detect the current platform.
platform = platform_detect.platform_detect()
# Pick the right extension to compile based on the platform.
extensions = []
if not is_binary_install():
print('Skipped loading platform-specific extensions for Adafruit_DHT (we are generating a cross-platform source distribution).')
elif platform == platform_detect.RASPBERRY_PI:
# Get the Pi version (1 or 2)
if pi_version is None:
pi_version = platform_detect.pi_version()
# Build the right extension depending on the Pi version.
if pi_version == 1:
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_Driver",
["source/_Raspberry_Pi_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi/pi_dht_read.c", "source/Raspberry_Pi/pi_mmio.c"],
libraries=['rt'],
extra_compile_args=['-std=gnu99']))
elif pi_version == 2:
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_2_Driver",
["source/_Raspberry_Pi_2_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi_2/pi_2_dht_read.c", "source/Raspberry_Pi_2/pi_2_mmio.c"],
libraries=['rt'],
extra_compile_args=['-std=gnu99']))
elif pi_version == 3:
extensions.append(Extension("Adafruit_DHT.Raspberry_Pi_2_Driver",
["source/_Raspberry_Pi_2_Driver.c", "source/common_dht_read.c", "source/Raspberry_Pi_2/pi_2_dht_read.c", "source/Raspberry_Pi_2/pi_2_mmio.c"],
libraries=['rt'],
extra_compile_args=['-std=gnu99']))
else:
raise RuntimeError('Detected Pi version that has no appropriate driver available.')
elif platform == platform_detect.BEAGLEBONE_BLACK:
extensions.append(Extension("Adafruit_DHT.Beaglebone_Black_Driver",
["source/_Beaglebone_Black_Driver.c", "source/common_dht_read.c", "source/Beaglebone_Black/bbb_dht_read.c", "source/Beaglebone_Black/bbb_mmio.c"],
libraries=['rt'],
extra_compile_args=['-std=gnu99']))
elif platform == 'TEST':
extensions.append(Extension("Adafruit_DHT.Test_Driver",
["source/_Test_Driver.c", "source/Test/test_dht_read.c"],
extra_compile_args=['-std=gnu99']))
else:
print('Could not detect if running on the Raspberry Pi or Beaglebone Black. If this failure is unexpected, you can run again with --force-pi or --force-bbb parameter to force using the Raspberry Pi or Beaglebone Black respectively.')
sys.exit(1)
classifiers = ['Development Status :: 4 - Beta',
'Operating System :: POSIX :: Linux',
'License :: OSI Approved :: MIT License',
'Intended Audience :: Developers',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Topic :: Software Development',
'Topic :: System :: Hardware']
# Call setuptools setup function to install package.
setup(name = 'Adafruit_DHT',
version = '1.4.0',
author = 'Tony DiCola',
author_email = 'tdicola@adafruit.com',
description = 'Library to get readings from the DHT11, DHT22, and AM2302 humidity and temperature sensors on a Raspberry Pi or Beaglebone Black.',
long_description = read('README.md'),
license = 'MIT',
classifiers = classifiers,
url = 'https://github.com/adafruit/Adafruit_Python_DHT/',
packages = find_packages(),
ext_modules = extensions)
@@ -0,0 +1,154 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <stdlib.h>
#include <string.h>
#include "bbb_dht_read.h"
#include "bbb_mmio.h"
// This is the only processor specific magic value, the maximum amount of time to
// spin in a loop before bailing out and considering the read a timeout. This should
// be a high value, but if you're running on a much faster platform than a Raspberry
// Pi or Beaglebone Black then it might need to be increased.
#define DHT_MAXCOUNT 32000
// Number of bit pulses to expect from the DHT. Note that this is 41 because
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
// the data afterwards.
#define DHT_PULSES 41
int bbb_dht_read(int type, int gpio_base, int gpio_number, float* humidity, float* temperature) {
// Validate humidity and temperature arguments and set them to zero.
if (humidity == NULL || temperature == NULL) {
return DHT_ERROR_ARGUMENT;
}
*temperature = 0.0f;
*humidity = 0.0f;
// Store the count that each DHT bit pulse is low and high.
// Make sure array is initialized to start at zero.
int pulseCounts[DHT_PULSES*2] = {0};
// Get GPIO pin and set it as an output.
gpio_t pin;
if (bbb_mmio_get_gpio(gpio_base, gpio_number, &pin) < 0) {
return DHT_ERROR_GPIO;
}
bbb_mmio_set_output(pin);
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
set_max_priority();
// Set pin high for ~500 milliseconds.
bbb_mmio_set_high(pin);
sleep_milliseconds(500);
// The next calls are timing critical and care should be taken
// to ensure no unnecssary work is done below.
// Set pin low for ~20 milliseconds.
bbb_mmio_set_low(pin);
busy_wait_milliseconds(20);
// Set pin as input.
bbb_mmio_set_input(pin);
// Wait for DHT to pull pin low.
uint32_t count = 0;
while (bbb_mmio_input(pin)) {
if (++count >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Record pulse widths for the expected result bits.
for (int i=0; i < DHT_PULSES*2; i+=2) {
// Count how long pin is low and store in pulseCounts[i]
while (!bbb_mmio_input(pin)) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Count how long pin is high and store in pulseCounts[i+1]
while (bbb_mmio_input(pin)) {
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
}
// Done with timing critical code, now interpret the results.
// Drop back to normal priority.
set_default_priority();
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
// Ignore the first two readings because they are a constant 80 microsecond pulse.
uint32_t threshold = 0;
for (int i=2; i < DHT_PULSES*2; i+=2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES-1;
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
// then it must be a ~70us 1 pulse.
uint8_t data[5] = {0};
for (int i=3; i < DHT_PULSES*2; i+=2) {
int index = (i-3)/16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
// One bit for long pulse.
data[index] |= 1;
}
// Else zero bit for short pulse.
}
// Useful debug info:
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
// Verify checksum of received data.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
if (type == DHT11) {
// Get humidity and temp for DHT11 sensor.
*humidity = (float)data[0];
*temperature = (float)data[2];
}
else if (type == DHT22) {
// Calculate humidity and temp for DHT22 sensor.
*humidity = (data[0] * 256 + data[1]) / 10.0f;
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
if (data[2] & 0x80) {
*temperature *= -1.0f;
}
}
return DHT_SUCCESS;
}
else {
return DHT_ERROR_CHECKSUM;
}
}
@@ -0,0 +1,33 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#ifndef BBB_DHT_READ_H
#define BBB_DHT_READ_H
#include "../common_dht_read.h"
// Read DHT sensor connected to GPIO bin GPIO<base>_<number>, for example P8_11 is GPIO1_13 with
// base = 1 and number = 13. Humidity and temperature will be returned in the provided parameters.
// If a successfull reading could be made a value of 0 (DHT_SUCCESS) will be returned. If there
// was an error reading the sensor a negative value will be returned. Some errors can be ignored
// and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
int bbb_dht_read(int type, int gpio_base, int gpio_number, float* humidity, float* temperature);
#endif
@@ -0,0 +1,73 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "bbb_mmio.h"
#define GPIO_LENGTH 4096
#define GPIO0_ADDR 0x44E07000
#define GPIO1_ADDR 0x4804C000
#define GPIO2_ADDR 0x481AC000
#define GPIO3_ADDR 0x481AF000
// Store mapping of GPIO base number to GPIO address.
static uint32_t gpio_addresses[4] = { GPIO0_ADDR, GPIO1_ADDR, GPIO2_ADDR, GPIO3_ADDR };
// Cache memory-mapped GPIO addresses.
static volatile uint32_t* gpio_base[4] = { NULL };
int bbb_mmio_get_gpio(int base, int number, gpio_t* gpio) {
// Validate input parameters.
if (gpio == NULL) {
return MMIO_ERROR_ARGUMENT;
}
if (base < 0 || base > 3) {
return MMIO_ERROR_ARGUMENT;
}
if (number < 0 || number > 31) {
return MMIO_ERROR_ARGUMENT;
}
// Map GPIO memory if its hasn't been mapped already.
if (gpio_base[base] == NULL) {
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
// Error opening /dev/mem. Probably not running as root.
return MMIO_ERROR_DEVMEM;
}
// Map GPIO memory to location in process space.
gpio_base[base] = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gpio_addresses[base]);
if (gpio_base[base] == MAP_FAILED) {
// Don't save the result if the memory mapping failed.
gpio_base[base] = NULL;
return MMIO_ERROR_MMAP;
}
}
// Initialize and set GPIO fields.
memset(gpio, 0, sizeof(gpio));
gpio->base = gpio_base[base];
gpio->number = number;
return MMIO_SUCCESS;
}
@@ -0,0 +1,101 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
// Simple fast memory-mapped GPIO library for the Beaglebone Black.
// Allows reading and writing GPIO at very high speeds, up to ~2.6mhz!
/*
// Example usage:
#include <stdio.h>
#include "bbb_mmio.h"
int main(int argc, char* argv[]) {
// Get GPIO pin.
// See the giant table of of pins in the system reference manual for details
// on the base and number for a given GPIO:
// https://github.com/CircuitCo/BeagleBone-Black/blob/master/BBB_SRM.pdf?raw=true
// Section 7 Connectors, table 12 shows P8_11 maps to GPIO1_13, so 1 is the
// gpio base and 13 is the gpio number.
gpio_t p8_11;
if (bbb_mmio_get_gpio(1, 13, &p8_11) < 0) {
printf("Couldn't get requested GPIO pin!\n");
return 1;
}
// Set pin as output.
bbb_mmio_set_output(p8_11);
// Toggle the pin high and low as fast as possible.
// This generates a signal at about 2.6mhz in my tests.
// Each pulse high/low is only about 200 nanoseconds long!
while (1) {
bbb_mmio_set_high(p8_11);
bbb_mmio_set_low(p8_11);
}
return 0;
}
*/
#ifndef BBB_MMIO_H
#define BBB_MMIO_H
#include <stdint.h>
#define MMIO_SUCCESS 0
#define MMIO_ERROR_ARGUMENT -1
#define MMIO_ERROR_DEVMEM -2
#define MMIO_ERROR_MMAP -3
#define MMIO_OE_ADDR 0x134
#define MMIO_GPIO_DATAOUT 0x13C
#define MMIO_GPIO_DATAIN 0x138
#define MMIO_GPIO_CLEARDATAOUT 0x190
#define MMIO_GPIO_SETDATAOUT 0x194
// Define struct to represent a GPIO pin based on its base memory address and number.
typedef struct {
volatile uint32_t* base;
int number;
} gpio_t;
int bbb_mmio_get_gpio(int base, int number, gpio_t* gpio);
static inline void bbb_mmio_set_output(gpio_t gpio) {
gpio.base[MMIO_OE_ADDR/4] &= (0xFFFFFFFF ^ (1 << gpio.number));
}
static inline void bbb_mmio_set_input(gpio_t gpio) {
gpio.base[MMIO_OE_ADDR/4] |= (1 << gpio.number);
}
static inline void bbb_mmio_set_high(gpio_t gpio) {
gpio.base[MMIO_GPIO_SETDATAOUT/4] = 1 << gpio.number;
}
static inline void bbb_mmio_set_low(gpio_t gpio) {
gpio.base[MMIO_GPIO_CLEARDATAOUT/4] = 1 << gpio.number;
}
static inline uint32_t bbb_mmio_input(gpio_t gpio) {
return gpio.base[MMIO_GPIO_DATAIN/4] & (1 << gpio.number);
}
#endif
@@ -0,0 +1,158 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <stdbool.h>
#include <stdlib.h>
#include "pi_dht_read.h"
#include "pi_mmio.h"
// This is the only processor specific magic value, the maximum amount of time to
// spin in a loop before bailing out and considering the read a timeout. This should
// be a high value, but if you're running on a much faster platform than a Raspberry
// Pi or Beaglebone Black then it might need to be increased.
#define DHT_MAXCOUNT 32000
// Number of bit pulses to expect from the DHT. Note that this is 41 because
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
// the data afterwards.
#define DHT_PULSES 41
int pi_dht_read(int type, int pin, float* humidity, float* temperature) {
// Validate humidity and temperature arguments and set them to zero.
if (humidity == NULL || temperature == NULL) {
return DHT_ERROR_ARGUMENT;
}
*temperature = 0.0f;
*humidity = 0.0f;
// Initialize GPIO library.
if (pi_mmio_init() < 0) {
return DHT_ERROR_GPIO;
}
// Store the count that each DHT bit pulse is low and high.
// Make sure array is initialized to start at zero.
int pulseCounts[DHT_PULSES*2] = {0};
// Set pin to output.
pi_mmio_set_output(pin);
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
set_max_priority();
// Set pin high for ~500 milliseconds.
pi_mmio_set_high(pin);
sleep_milliseconds(500);
// The next calls are timing critical and care should be taken
// to ensure no unnecssary work is done below.
// Set pin low for ~20 milliseconds.
pi_mmio_set_low(pin);
busy_wait_milliseconds(20);
// Set pin at input.
pi_mmio_set_input(pin);
// Need a very short delay before reading pins or else value is sometimes still low.
for (volatile int i = 0; i < 500; ++i) {
}
// Wait for DHT to pull pin low.
uint32_t count = 0;
while (pi_mmio_input(pin)) {
if (++count >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Record pulse widths for the expected result bits.
for (int i=0; i < DHT_PULSES*2; i+=2) {
// Count how long pin is low and store in pulseCounts[i]
while (!pi_mmio_input(pin)) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Count how long pin is high and store in pulseCounts[i+1]
while (pi_mmio_input(pin)) {
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
}
// Done with timing critical code, now interpret the results.
// Drop back to normal priority.
set_default_priority();
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
// Ignore the first two readings because they are a constant 80 microsecond pulse.
uint32_t threshold = 0;
for (int i=2; i < DHT_PULSES*2; i+=2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES-1;
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
// then it must be a ~70us 1 pulse.
uint8_t data[5] = {0};
for (int i=3; i < DHT_PULSES*2; i+=2) {
int index = (i-3)/16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
// One bit for long pulse.
data[index] |= 1;
}
// Else zero bit for short pulse.
}
// Useful debug info:
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
// Verify checksum of received data.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
if (type == DHT11) {
// Get humidity and temp for DHT11 sensor.
*humidity = (float)data[0];
*temperature = (float)data[2];
}
else if (type == DHT22) {
// Calculate humidity and temp for DHT22 sensor.
*humidity = (data[0] * 256 + data[1]) / 10.0f;
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
if (data[2] & 0x80) {
*temperature *= -1.0f;
}
}
return DHT_SUCCESS;
}
else {
return DHT_ERROR_CHECKSUM;
}
}
@@ -0,0 +1,32 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#ifndef PI_DHT_READ_H
#define PI_DHT_READ_H
#include "../common_dht_read.h"
// Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be
// returned in the provided parameters. If a successfull reading could be made a value of 0
// (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will
// be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
int pi_dht_read(int sensor, int pin, float* humidity, float* temperature);
#endif
+63
View File
@@ -0,0 +1,63 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// 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.
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "pi_mmio.h"
#define BASE 0x20000000
#define GPIO_BASE (BASE + 0x200000)
#define GPIO_LENGTH 4096
volatile uint32_t* pi_mmio_gpio = NULL;
int pi_mmio_init(void) {
if (pi_mmio_gpio == NULL) {
int fd;
// On older kernels user readable /dev/gpiomem might not exists.
// Falls back to root-only /dev/mem.
if( access( "/dev/gpiomem", F_OK ) != -1 ) {
fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
} else {
fd = open("/dev/mem", O_RDWR | O_SYNC);
}
if (fd == -1) {
// Error opening /dev/gpiomem.
return MMIO_ERROR_DEVMEM;
}
// Map GPIO memory to location in process space.
pi_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE);
close(fd);
if (pi_mmio_gpio == MAP_FAILED) {
// Don't save the result if the memory mapping failed.
pi_mmio_gpio = NULL;
return MMIO_ERROR_MMAP;
}
}
return MMIO_SUCCESS;
}
+61
View File
@@ -0,0 +1,61 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// 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.
// Simple fast memory-mapped GPIO library for the Raspberry Pi.
#ifndef PI_MMIO_H
#define PI_MMIO_H
#include <stdint.h>
#define MMIO_SUCCESS 0
#define MMIO_ERROR_DEVMEM -1
#define MMIO_ERROR_MMAP -2
extern volatile uint32_t* pi_mmio_gpio;
int pi_mmio_init(void);
static inline void pi_mmio_set_input(const int gpio_number) {
// Set GPIO register to 000 for specified GPIO number.
*(pi_mmio_gpio+((gpio_number)/10)) &= ~(7<<(((gpio_number)%10)*3));
}
static inline void pi_mmio_set_output(const int gpio_number) {
// First set to 000 using input function.
pi_mmio_set_input(gpio_number);
// Next set bit 0 to 1 to set output.
*(pi_mmio_gpio+((gpio_number)/10)) |= (1<<(((gpio_number)%10)*3));
}
static inline void pi_mmio_set_high(const int gpio_number) {
*(pi_mmio_gpio+7) = 1 << gpio_number;
}
static inline void pi_mmio_set_low(const int gpio_number) {
*(pi_mmio_gpio+10) = 1 << gpio_number;
}
static inline uint32_t pi_mmio_input(const int gpio_number) {
return *(pi_mmio_gpio+13) & (1 << gpio_number);
}
#endif
@@ -0,0 +1,158 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <stdbool.h>
#include <stdlib.h>
#include "pi_2_dht_read.h"
#include "pi_2_mmio.h"
// This is the only processor specific magic value, the maximum amount of time to
// spin in a loop before bailing out and considering the read a timeout. This should
// be a high value, but if you're running on a much faster platform than a Raspberry
// Pi or Beaglebone Black then it might need to be increased.
#define DHT_MAXCOUNT 32000
// Number of bit pulses to expect from the DHT. Note that this is 41 because
// the first pulse is a constant 50 microsecond pulse, with 40 pulses to represent
// the data afterwards.
#define DHT_PULSES 41
int pi_2_dht_read(int type, int pin, float* humidity, float* temperature) {
// Validate humidity and temperature arguments and set them to zero.
if (humidity == NULL || temperature == NULL) {
return DHT_ERROR_ARGUMENT;
}
*temperature = 0.0f;
*humidity = 0.0f;
// Initialize GPIO library.
if (pi_2_mmio_init() < 0) {
return DHT_ERROR_GPIO;
}
// Store the count that each DHT bit pulse is low and high.
// Make sure array is initialized to start at zero.
int pulseCounts[DHT_PULSES*2] = {0};
// Set pin to output.
pi_2_mmio_set_output(pin);
// Bump up process priority and change scheduler to try to try to make process more 'real time'.
set_max_priority();
// Set pin high for ~500 milliseconds.
pi_2_mmio_set_high(pin);
sleep_milliseconds(500);
// The next calls are timing critical and care should be taken
// to ensure no unnecssary work is done below.
// Set pin low for ~20 milliseconds.
pi_2_mmio_set_low(pin);
busy_wait_milliseconds(20);
// Set pin at input.
pi_2_mmio_set_input(pin);
// Need a very short delay before reading pins or else value is sometimes still low.
for (volatile int i = 0; i < 50; ++i) {
}
// Wait for DHT to pull pin low.
uint32_t count = 0;
while (pi_2_mmio_input(pin)) {
if (++count >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Record pulse widths for the expected result bits.
for (int i=0; i < DHT_PULSES*2; i+=2) {
// Count how long pin is low and store in pulseCounts[i]
while (!pi_2_mmio_input(pin)) {
if (++pulseCounts[i] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
// Count how long pin is high and store in pulseCounts[i+1]
while (pi_2_mmio_input(pin)) {
if (++pulseCounts[i+1] >= DHT_MAXCOUNT) {
// Timeout waiting for response.
set_default_priority();
return DHT_ERROR_TIMEOUT;
}
}
}
// Done with timing critical code, now interpret the results.
// Drop back to normal priority.
set_default_priority();
// Compute the average low pulse width to use as a 50 microsecond reference threshold.
// Ignore the first two readings because they are a constant 80 microsecond pulse.
uint32_t threshold = 0;
for (int i=2; i < DHT_PULSES*2; i+=2) {
threshold += pulseCounts[i];
}
threshold /= DHT_PULSES-1;
// Interpret each high pulse as a 0 or 1 by comparing it to the 50us reference.
// If the count is less than 50us it must be a ~28us 0 pulse, and if it's higher
// then it must be a ~70us 1 pulse.
uint8_t data[5] = {0};
for (int i=3; i < DHT_PULSES*2; i+=2) {
int index = (i-3)/16;
data[index] <<= 1;
if (pulseCounts[i] >= threshold) {
// One bit for long pulse.
data[index] |= 1;
}
// Else zero bit for short pulse.
}
// Useful debug info:
//printf("Data: 0x%x 0x%x 0x%x 0x%x 0x%x\n", data[0], data[1], data[2], data[3], data[4]);
// Verify checksum of received data.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
if (type == DHT11) {
// Get humidity and temp for DHT11 sensor.
*humidity = (float)data[0];
*temperature = (float)data[2];
}
else if (type == DHT22) {
// Calculate humidity and temp for DHT22 sensor.
*humidity = (data[0] * 256 + data[1]) / 10.0f;
*temperature = ((data[2] & 0x7F) * 256 + data[3]) / 10.0f;
if (data[2] & 0x80) {
*temperature *= -1.0f;
}
}
return DHT_SUCCESS;
}
else {
return DHT_ERROR_CHECKSUM;
}
}
@@ -0,0 +1,32 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#ifndef PI_2_DHT_READ_H
#define PI_2_DHT_READ_H
#include "../common_dht_read.h"
// Read DHT sensor connected to GPIO pin (using BCM numbering). Humidity and temperature will be
// returned in the provided parameters. If a successfull reading could be made a value of 0
// (DHT_SUCCESS) will be returned. If there was an error reading the sensor a negative value will
// be returned. Some errors can be ignored and retried, specifically DHT_ERROR_TIMEOUT or DHT_ERROR_CHECKSUM.
int pi_2_dht_read(int sensor, int pin, float* humidity, float* temperature);
#endif
@@ -0,0 +1,71 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// 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.
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "pi_2_mmio.h"
#define GPIO_BASE_OFFSET 0x200000
#define GPIO_LENGTH 4096
volatile uint32_t* pi_2_mmio_gpio = NULL;
int pi_2_mmio_init(void) {
if (pi_2_mmio_gpio == NULL) {
// Check for GPIO and peripheral addresses from device tree.
// Adapted from code in the RPi.GPIO library at:
// http://sourceforge.net/p/raspberry-gpio-python/
FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
if (fp == NULL) {
return MMIO_ERROR_OFFSET;
}
fseek(fp, 4, SEEK_SET);
unsigned char buf[4];
if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) {
return MMIO_ERROR_OFFSET;
}
uint32_t peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
uint32_t gpio_base = peri_base + GPIO_BASE_OFFSET;
fclose(fp);
int fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
if (fd == -1) {
// Error opening /dev/gpiomem.
return MMIO_ERROR_DEVMEM;
}
// Map GPIO memory to location in process space.
pi_2_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, gpio_base);
close(fd);
if (pi_2_mmio_gpio == MAP_FAILED) {
// Don't save the result if the memory mapping failed.
pi_2_mmio_gpio = NULL;
return MMIO_ERROR_MMAP;
}
}
return MMIO_SUCCESS;
}
@@ -0,0 +1,62 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Based on code from Gert van Loo & Dom: http://elinux.org/RPi_Low-level_peripherals#GPIO_Code_examples
// 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.
// Simple fast memory-mapped GPIO library for the Raspberry Pi.
#ifndef PI_2_MMIO_H
#define PI_2_MMIO_H
#include <stdint.h>
#define MMIO_SUCCESS 0
#define MMIO_ERROR_DEVMEM -1
#define MMIO_ERROR_MMAP -2
#define MMIO_ERROR_OFFSET -3
extern volatile uint32_t* pi_2_mmio_gpio;
int pi_2_mmio_init(void);
static inline void pi_2_mmio_set_input(const int gpio_number) {
// Set GPIO register to 000 for specified GPIO number.
*(pi_2_mmio_gpio+((gpio_number)/10)) &= ~(7<<(((gpio_number)%10)*3));
}
static inline void pi_2_mmio_set_output(const int gpio_number) {
// First set to 000 using input function.
pi_2_mmio_set_input(gpio_number);
// Next set bit 0 to 1 to set output.
*(pi_2_mmio_gpio+((gpio_number)/10)) |= (1<<(((gpio_number)%10)*3));
}
static inline void pi_2_mmio_set_high(const int gpio_number) {
*(pi_2_mmio_gpio+7) = 1 << gpio_number;
}
static inline void pi_2_mmio_set_low(const int gpio_number) {
*(pi_2_mmio_gpio+10) = 1 << gpio_number;
}
static inline uint32_t pi_2_mmio_input(const int gpio_number) {
return *(pi_2_mmio_gpio+13) & (1 << gpio_number);
}
#endif
+34
View File
@@ -0,0 +1,34 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <stdlib.h>
#include "test_dht_read.h"
int test_dht_read(int type, int pin, float* humidity, float* temperature) {
// Validate humidity and temperature arguments and set them to zero.
if (humidity == NULL || temperature == NULL) {
return -1;
}
*temperature = 42.0f;
*humidity = 50.0f;
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#ifndef TEST_DHT_READ_H
#define TEST_DHT_READ_H
int test_dht_read(int sensor, int pin, float* humidity, float* temperature);
#endif
@@ -0,0 +1,73 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <Python.h>
#include "Beaglebone_Black/bbb_dht_read.h"
// Wrap calling dht_read function and expose it as a DHT.read Python module & function.
static PyObject* Beaglebone_Black_Driver_read(PyObject *self, PyObject *args)
{
// Parse sensor and pin integer arguments.
int sensor, base, number;
if (!PyArg_ParseTuple(args, "iii", &sensor, &base, &number)) {
return NULL;
}
// Call dht_read and return result code, humidity, and temperature.
float humidity = 0, temperature = 0;
int result = bbb_dht_read(sensor, base, number, &humidity, &temperature);
return Py_BuildValue("iff", result, humidity, temperature);
}
// Boilerplate python module method list and initialization functions below.
static PyMethodDef module_methods[] = {
{"read", Beaglebone_Black_Driver_read, METH_VARARGS, "Read DHT sensor value on a Beaglebone Black."},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef bbb_dht_module = {
PyModuleDef_HEAD_INIT,
"Beaglebone_Black_Driver", // name of module
NULL, // module documentation, may be NULL
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
module_methods
};
#endif
#if PY_MAJOR_VERSION > 2
PyMODINIT_FUNC PyInit_Beaglebone_Black_Driver(void)
#else
PyMODINIT_FUNC initBeaglebone_Black_Driver(void)
#endif
{
#if PY_MAJOR_VERSION > 2
PyObject* module = PyModule_Create(&bbb_dht_module);
#else
Py_InitModule("Beaglebone_Black_Driver", module_methods);
#endif
#if PY_MAJOR_VERSION > 2
return module;
#else
return;
#endif
}
@@ -0,0 +1,73 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <Python.h>
#include "Raspberry_Pi_2/pi_2_dht_read.h"
// Wrap calling dht_read function and expose it as a DHT.read Python module & function.
static PyObject* Raspberry_Pi_2_Driver_read(PyObject *self, PyObject *args)
{
// Parse sensor and pin integer arguments.
int sensor, pin;
if (!PyArg_ParseTuple(args, "ii", &sensor, &pin)) {
return NULL;
}
// Call dht_read and return result code, humidity, and temperature.
float humidity = 0, temperature = 0;
int result = pi_2_dht_read(sensor, pin, &humidity, &temperature);
return Py_BuildValue("iff", result, humidity, temperature);
}
// Boilerplate python module method list and initialization functions below.
static PyMethodDef module_methods[] = {
{"read", Raspberry_Pi_2_Driver_read, METH_VARARGS, "Read DHT sensor value on a Raspberry Pi 2."},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef pi2_dht_module = {
PyModuleDef_HEAD_INIT,
"Raspberry_Pi_2_Driver", // name of module
NULL, // module documentation, may be NULL
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
module_methods
};
#endif
#if PY_MAJOR_VERSION > 2
PyMODINIT_FUNC PyInit_Raspberry_Pi_2_Driver(void)
#else
PyMODINIT_FUNC initRaspberry_Pi_2_Driver(void)
#endif
{
#if PY_MAJOR_VERSION > 2
PyObject* module = PyModule_Create(&pi2_dht_module);
#else
Py_InitModule("Raspberry_Pi_2_Driver", module_methods);
#endif
#if PY_MAJOR_VERSION > 2
return module;
#else
return;
#endif
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <Python.h>
#include "Raspberry_Pi/pi_dht_read.h"
// Wrap calling dht_read function and expose it as a DHT.read Python module & function.
static PyObject* Raspberry_Pi_Driver_read(PyObject *self, PyObject *args)
{
// Parse sensor and pin integer arguments.
int sensor, pin;
if (!PyArg_ParseTuple(args, "ii", &sensor, &pin)) {
return NULL;
}
// Call dht_read and return result code, humidity, and temperature.
float humidity = 0, temperature = 0;
int result = pi_dht_read(sensor, pin, &humidity, &temperature);
return Py_BuildValue("iff", result, humidity, temperature);
}
// Boilerplate python module method list and initialization functions below.
static PyMethodDef module_methods[] = {
{"read", Raspberry_Pi_Driver_read, METH_VARARGS, "Read DHT sensor value on a Raspberry Pi."},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef pi_dht_module = {
PyModuleDef_HEAD_INIT,
"Raspberry_Pi_Driver", // name of module
NULL, // module documentation, may be NULL
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
module_methods
};
#endif
#if PY_MAJOR_VERSION > 2
PyMODINIT_FUNC PyInit_Raspberry_Pi_Driver(void)
#else
PyMODINIT_FUNC initRaspberry_Pi_Driver(void)
#endif
{
#if PY_MAJOR_VERSION > 2
PyObject* module = PyModule_Create(&pi_dht_module);
#else
Py_InitModule("Raspberry_Pi_Driver", module_methods);
#endif
#if PY_MAJOR_VERSION > 2
return module;
#else
return;
#endif
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <Python.h>
#include "Test/test_dht_read.h"
// Wrap calling dht_read function and expose it as a DHT.read Python module & function.
static PyObject* Test_Driver_read(PyObject *self, PyObject *args)
{
// Parse sensor and pin integer arguments.
int sensor, pin;
if (!PyArg_ParseTuple(args, "ii", &sensor, &pin)) {
return NULL;
}
// Call dht_read and return result code, humidity, and temperature.
float humidity = 0, temperature = 0;
int result = test_dht_read(sensor, pin, &humidity, &temperature);
return Py_BuildValue("iff", result, humidity, temperature);
}
// Boilerplate python module method list and initialization functions below.
static PyMethodDef module_methods[] = {
{"read", Test_Driver_read, METH_VARARGS, "Mock DHT read function."},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION > 2
static struct PyModuleDef test_dht_module = {
PyModuleDef_HEAD_INIT,
"Test_Driver", // name of module
NULL, // module documentation, may be NULL
-1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables.
module_methods
};
#endif
#if PY_MAJOR_VERSION > 2
PyMODINIT_FUNC PyInit_Test_Driver(void)
#else
PyMODINIT_FUNC initTest_Driver(void)
#endif
{
#if PY_MAJOR_VERSION > 2
PyObject* module = PyModule_Create(&test_dht_module);
#else
Py_InitModule("Test_Driver", module_methods);
#endif
#if PY_MAJOR_VERSION > 2
return module;
#else
return;
#endif
}
+66
View File
@@ -0,0 +1,66 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "common_dht_read.h"
void busy_wait_milliseconds(uint32_t millis) {
// Set delay time period.
struct timeval deltatime;
deltatime.tv_sec = millis / 1000;
deltatime.tv_usec = (millis % 1000) * 1000;
struct timeval walltime;
// Get current time and add delay to find end time.
gettimeofday(&walltime, NULL);
struct timeval endtime;
timeradd(&walltime, &deltatime, &endtime);
// Tight loop to waste time (and CPU) until enough time as elapsed.
while (timercmp(&walltime, &endtime, <)) {
gettimeofday(&walltime, NULL);
}
}
void sleep_milliseconds(uint32_t millis) {
struct timespec sleep;
sleep.tv_sec = millis / 1000;
sleep.tv_nsec = (millis % 1000) * 1000000L;
while (clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep, &sleep) && errno == EINTR);
}
void set_max_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);
}
void set_default_priority(void) {
struct sched_param sched;
memset(&sched, 0, sizeof(sched));
// Go back to default scheduler with default 0 priority.
sched.sched_priority = 0;
sched_setscheduler(0, SCHED_OTHER, &sched);
}
+51
View File
@@ -0,0 +1,51 @@
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// 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.
#ifndef COMMON_DHT_READ_H
#define COMMON_DHT_READ_H
#include <stdint.h>
// Define errors and return values.
#define DHT_ERROR_TIMEOUT -1
#define DHT_ERROR_CHECKSUM -2
#define DHT_ERROR_ARGUMENT -3
#define DHT_ERROR_GPIO -4
#define DHT_SUCCESS 0
// Define sensor types.
#define DHT11 11
#define DHT22 22
#define AM2302 22
// Busy wait delay for most accurate timing, but high CPU usage.
// Only use this for short periods of time (a few hundred milliseconds at most)!
void busy_wait_milliseconds(uint32_t millis);
// General delay that sleeps so CPU usage is low, but accuracy is potentially bad.
void sleep_milliseconds(uint32_t millis);
// Increase scheduling priority and algorithm to try to get 'real time' results.
void set_max_priority(void);
// Drop scheduling priority back to normal/default.
void set_default_priority(void);
#endif
+19
View File
@@ -0,0 +1,19 @@
#MESSAGE TEMPERATURE/HUMIDITE
#
if {$cmd == "11"} {
set temphum [exec sudo python /home/pi/Adafruit_Python_DHT/examples/AdafruitDHT.py 11 4];
set temperature [string range $temphum 5 8]
set humidity [string range $temphum 21 24]
#TEMPERATURE EXTERIEUR:
puts " Température: $temperature °C"
playMsg "SVXCard/Weatherstation" "tempext";
playTemp $temperature;
#HUMIDITY OUT
puts "Humidité $humidity %"
playMsg "SVXCard/Weatherstation" "humidityout";
playNumber $humidity;
playMsg "Default" "percent";
return 1
}
+56
View File
@@ -0,0 +1,56 @@
# 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
}
+3
View File
@@ -0,0 +1,3 @@
*.pyc
.DS_Store
status.wav
+21
View File
@@ -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.
+997
View File
@@ -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
#
+191
View File
@@ -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 !
+91
View File
@@ -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
+46
View File
@@ -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
+157
View File
@@ -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
+59
View File
@@ -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': ''
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.