github upload
This commit is contained in:
105
WiFi.py
Normal file
105
WiFi.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import network
|
||||
import utime
|
||||
import machine
|
||||
|
||||
_DEBUG = False
|
||||
|
||||
|
||||
class NetSet(object):
|
||||
|
||||
def __init__(self, wifi_type):
|
||||
self.sta = network.WLAN(network.STA_IF)
|
||||
self.ap = network.WLAN(network.AP_IF)
|
||||
if wifi_type == 'infra':
|
||||
if _DEBUG:
|
||||
print("Disabling AP")
|
||||
self.ap.active(False)
|
||||
if _DEBUG:
|
||||
print("Activating INFRA")
|
||||
self.sta.active(True)
|
||||
self.sta.isconnected() # False, it should be # Comments by Yoda
|
||||
self._SSID = None
|
||||
self._PASS = None
|
||||
self._TIMEOUT = None
|
||||
elif wifi_type == 'ap':
|
||||
if _DEBUG:
|
||||
print("Disabling INFRA")
|
||||
self.ap.active(True)
|
||||
if _DEBUG:
|
||||
print("Activating AP")
|
||||
self.sta.active(False)
|
||||
self.sta.isconnected() # False, it should be # Comments by Yoda
|
||||
self._SSID = None
|
||||
self._PASS = None
|
||||
self._TIMEOUT = None
|
||||
|
||||
def connectInfraGo(self, _timeout):
|
||||
if _DEBUG:
|
||||
print("Connecting to infra")
|
||||
self.sta.connect(self._SSID, self._PASS)
|
||||
if _DEBUG:
|
||||
print("Let's wait for the network to come up")
|
||||
while not (self.sta.isconnected()):
|
||||
if _timeout > 0:
|
||||
print("Trying... {} more times".format(_timeout))
|
||||
utime.sleep_ms(1001)
|
||||
_timeout -= 1
|
||||
else:
|
||||
print("Out of retrys")
|
||||
return False
|
||||
network_config = self.sta.ifconfig()
|
||||
return network_config
|
||||
|
||||
def connectInfra(self, _SSID, _PASS, _TIMEOUT):
|
||||
self._SSID = _SSID
|
||||
self._PASS = _PASS
|
||||
try:
|
||||
net_conf_result = self.connectInfraGo(_TIMEOUT)
|
||||
utime.sleep_ms(100)
|
||||
if net_conf_result:
|
||||
return {
|
||||
'ip': net_conf_result[0],
|
||||
'mask': net_conf_result[1],
|
||||
'gw': net_conf_result[2],
|
||||
'dns': net_conf_result[3] }
|
||||
else:
|
||||
return False
|
||||
except Exception as e:
|
||||
print("ERROR: Network configuration failed with: {}".format(e))
|
||||
return False
|
||||
|
||||
def connectAp(self):
|
||||
# TBI
|
||||
pass
|
||||
|
||||
def readNetworkConfig(self):
|
||||
self.config_dict = {}
|
||||
try:
|
||||
with open('inet.conf', 'r') as conf_handler:
|
||||
for item in conf_handler.readlines():
|
||||
option = item.split("=")[0].strip()
|
||||
if len(item.split("=")) == 2 and '#' not in option:
|
||||
value = item.split("=")[1].strip()
|
||||
self.config_dict.update({option: value})
|
||||
else:
|
||||
if _DEBUG:
|
||||
if '#' in option:
|
||||
print(b"COMMENT in config")
|
||||
else:
|
||||
print(b"WARNING: Fucked up option, make it better")
|
||||
except Exception as e:
|
||||
if _DEBUG:
|
||||
print("WARNING: Errors in INFRA config, still going for AP")
|
||||
return False
|
||||
if _DEBUG:
|
||||
print("CONFIG DICT: {}".format(self.config_dict))
|
||||
self._SSID = self.config_dict['_SSID']
|
||||
self._PASS = self.config_dict['_PASS']
|
||||
self._TIMEOUT = int(self.config_dict['_TIMEOUT'])
|
||||
self._INFLUX_HOST = self.config_dict['_INFLUX_HOST']
|
||||
self._INFLUX_PORT = self.config_dict['_INFLUX_PORT']
|
||||
self._INFLUX_USER = self.config_dict['_INFLUX_USER']
|
||||
self._INFLUX_PASS = self.config_dict['_INFLUX_PASS']
|
||||
self._INF_DB_WEATHER = self.config_dict['_INF_DB_WEATHER']
|
||||
self._INF_DB_STATUS = self.config_dict['_INF_DB_STATUS']
|
||||
self._INF_DB_RAW = self.config_dict['_INF_DB_RAW']
|
||||
3
boot.py
Normal file
3
boot.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is executed on every boot (including wake-boot from deepsleep)
|
||||
import gc
|
||||
gc.collect()
|
||||
BIN
cc1101_davis.mpy
Normal file
BIN
cc1101_davis.mpy
Normal file
Binary file not shown.
390
cc1101_davis.py
Normal file
390
cc1101_davis.py
Normal file
@@ -0,0 +1,390 @@
|
||||
import utime
|
||||
import gc
|
||||
import machine
|
||||
|
||||
ss = machine.Pin(15,machine.Pin.OUT) # Chip select / HCS
|
||||
so = machine.Pin(12) # HMISO
|
||||
si = machine.Pin(13) # HMOSI
|
||||
sck = machine.Pin(14) # HSCLK
|
||||
interrupt = machine.Pin(2) # Interrupt for packet available
|
||||
|
||||
gc.collect()
|
||||
|
||||
class CC1101(object):
|
||||
def __init__(self):
|
||||
self.debug = 1
|
||||
self.hspi = machine.SPI(1, baudrate=600000, polarity=0, phase=0)
|
||||
self.PA_TABLE = [0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0xC0]
|
||||
|
||||
self.FREQ_2 = [0x21, 0x21, 0x21, 0x21, 0x21]
|
||||
self.FREQ_1 = [0x62, 0x65, 0x67, 0x64, 0x66]
|
||||
self.FREQ_0 = [0xE2, 0x40, 0x9D, 0x11, 0x6F]
|
||||
|
||||
self.CRC_TABLE = [
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0]
|
||||
self.BUFFER_SIZE = 16
|
||||
self.DAVIS_PACKET_LENGTH = 10
|
||||
self.rxBuffer = []
|
||||
self.rxBufferIndex = 0
|
||||
self.rxBufferLength = 0
|
||||
self.hopIndex = 0
|
||||
self.freqComp = [0, 0, 0, 0, 0]
|
||||
|
||||
# CC1101 Transfer Types.
|
||||
self.WRITE_BURST = 0x40
|
||||
self.READ_SINGLE = 0x80
|
||||
self.READ_BURST = 0xC0
|
||||
|
||||
# Davis Register Configuration Settings.
|
||||
self.DAVIS_IOCFG2 = 0x2E # GDO2 Output Pin Configuration
|
||||
self.DAVIS_IOCFG1 = 0x2E # GDO1 Output Pin Configuration
|
||||
self.DAVIS_IOCFG0 = 0x01 # GDO0 Output Pin Configuration
|
||||
self.DAVIS_FIFOTHR = 0x42 # RX FIFO and TX FIFO Thresholds
|
||||
self.DAVIS_SYNC1 = 0xCB # Synchronization word, high byte
|
||||
self.DAVIS_SYNC0 = 0x89 # Synchronization word, low byte
|
||||
self.DAVIS_PKTLEN = 0x0A # Packet Length
|
||||
self.DAVIS_PKTCTRL1 = 0xC4 # Packet Automation Control
|
||||
self.DAVIS_PKTCTRL0 = 0x00 # Packet Automation Control
|
||||
self.DAVIS_ADDR = 0x00 # Device Address
|
||||
self.DAVIS_CHANNR = 0x00 # Channel Number
|
||||
self.DAVIS_FSCTRL1 = 0x06 # Frequency Synthesizer Control
|
||||
self.DAVIS_FSCTRL0 = 0xF0 # Frequency Synthesizer Control
|
||||
self.DAVIS_FREQ2 = 0x23 # Frequency Control Word, High Byte
|
||||
self.DAVIS_FREQ1 = 0x0D # Frequency Control Word, Middle Byte
|
||||
self.DAVIS_FREQ0 = 0x97 # Frequency Control Word, Low Byte
|
||||
self.DAVIS_MDMCFG4 = 0xC9 # Modem Configuration
|
||||
self.DAVIS_MDMCFG3 = 0x83 # Modem Configuration
|
||||
self.DAVIS_MDMCFG2 = 0x12 # Modem Configuration
|
||||
self.DAVIS_MDMCFG1 = 0x21 # Modem Configuration
|
||||
self.DAVIS_MDMCFG0 = 0xF9 # Modem Configuration
|
||||
self.DAVIS_DEVIATN = 0x24 # Modem Deviation Setting
|
||||
self.DAVIS_MCSM2 = 0x07 # Main Radio Control State Machine Configuration
|
||||
self.DAVIS_MCSM1 = 0x00 # Main Radio Control State Machine Configuration
|
||||
self.DAVIS_MCSM0 = 0x18 # Main Radio Control State Machine Configuration
|
||||
self.DAVIS_FOCCFG = 0x16 # Frequency Offset Compensation Configuration
|
||||
self.DAVIS_BSCFG = 0x6C # Bit Synchronization Configuration
|
||||
self.DAVIS_AGCCTRL2 = 0x43 # AGC Control
|
||||
self.DAVIS_AGCCTRL1 = 0x40 # AGC Control
|
||||
self.DAVIS_AGCCTRL0 = 0x91 # AGC Control
|
||||
self.DAVIS_WOREVT1 = 0x87 # High Byte Event0 Timeout
|
||||
self.DAVIS_WOREVT0 = 0x6B # Low Byte Event0 Timeout
|
||||
self.DAVIS_WORCTRL = 0xF8 # Wake On Radio Control
|
||||
self.DAVIS_FREND1 = 0x56 # Front End RX Configuration
|
||||
self.DAVIS_FREND0 = 0x10 # Front End TX Configuration
|
||||
self.DAVIS_FSCAL3 = 0xEF # Frequency Synthesizer Calibration
|
||||
self.DAVIS_FSCAL2 = 0x2B # Frequency Synthesizer Calibration
|
||||
self.DAVIS_FSCAL1 = 0x2F # Frequency Synthesizer Calibration
|
||||
self.DAVIS_FSCAL0 = 0x1F # Frequency Synthesizer Calibration
|
||||
self.DAVIS_RCCTRL1 = 0x00 # RC Oscillator Configuration
|
||||
self.DAVIS_RCCTRL0 = 0x00 # RC Oscillator Configuration
|
||||
self.DAVIS_FSTEST = 0x59 # Frequency Synthesizer Calibration Control
|
||||
self.DAVIS_PTEST = 0x7F # Production Test
|
||||
self.DAVIS_AGCTEST = 0x3F # AGC Test
|
||||
self.DAVIS_TEST2 = 0x81 # Various Test Settings
|
||||
self.DAVIS_TEST1 = 0x35 # Various Test Settings
|
||||
self.DAVIS_TEST0 = 0x09 # Various Test Settings
|
||||
|
||||
self.CC1101_IOCFG2 = 0x00 # GDO2 Output Pin Configuration
|
||||
self.CC1101_IOCFG1 = 0x01 # GDO1 Output Pin Configuration
|
||||
self.CC1101_IOCFG0 = 0x02 # GDO0 Output Pin Configuration
|
||||
self.CC1101_FIFOTHR = 0x03 # RX FIFO and TX FIFO Thresholds
|
||||
self.CC1101_SYNC1 = 0x04 # Sync Word, High Byte
|
||||
self.CC1101_SYNC0 = 0x05 # Sync Word, Low Byte
|
||||
self.CC1101_PKTLEN = 0x06 # Packet Length
|
||||
self.CC1101_PKTCTRL1 = 0x07 # Packet Automation Control
|
||||
self.CC1101_PKTCTRL0 = 0x08 # Packet Automation Control
|
||||
self.CC1101_ADDR = 0x09 # Device Address
|
||||
self.CC1101_CHANNR = 0x0A # Channel Number
|
||||
self.CC1101_FSCTRL1 = 0x0B # Frequency Synthesizer Control
|
||||
self.CC1101_FSCTRL0 = 0x0C # Frequency Synthesizer Control
|
||||
self.CC1101_FREQ2 = 0x0D # Frequency Control Word, High Byte
|
||||
self.CC1101_FREQ1 = 0x0E # Frequency Control Word, Middle Byte
|
||||
self.CC1101_FREQ0 = 0x0F # Frequency Control Word, Low Byte
|
||||
self.CC1101_MDMCFG4 = 0x10 # Modem Configuration
|
||||
self.CC1101_MDMCFG3 = 0x11 # Modem Configuration
|
||||
self.CC1101_MDMCFG2 = 0x12 # Modem Configuration
|
||||
self.CC1101_MDMCFG1 = 0x13 # Modem Configuration
|
||||
self.CC1101_MDMCFG0 = 0x14 # Modem Configuration
|
||||
self.CC1101_DEVIATN = 0x15 # Modem Deviation Setting
|
||||
self.CC1101_MCSM2 = 0x16 # Main Radio Control State Machine Configuration
|
||||
self.CC1101_MCSM1 = 0x17 # Main Radio Control State Machine Configuration
|
||||
self.CC1101_MCSM0 = 0x18 # Main Radio Control State Machine Configuration
|
||||
self.CC1101_FOCCFG = 0x19 # Frequency Offset Compensation Configuration
|
||||
self.CC1101_BSCFG = 0x1A # Bit Synchronization Configuration
|
||||
self.CC1101_AGCCTRL2 = 0x1B # AGC Control
|
||||
self.CC1101_AGCCTRL1 = 0x1C # AGC Control
|
||||
self.CC1101_AGCCTRL0 = 0x1D # AGC Control
|
||||
self.CC1101_WOREVT1 = 0x1E # High Byte Event0 Timeout
|
||||
self.CC1101_WOREVT0 = 0x1F # Low Byte Event0 Timeout
|
||||
self.CC1101_WORCTRL = 0x20 # Wake On Radio Control
|
||||
self.CC1101_FREND1 = 0x21 # Front End RX Configuration
|
||||
self.CC1101_FREND0 = 0x22 # Front End TX Configuration
|
||||
self.CC1101_FSCAL3 = 0x23 # Frequency Synthesizer Calibration
|
||||
self.CC1101_FSCAL2 = 0x24 # Frequency Synthesizer Calibration
|
||||
self.CC1101_FSCAL1 = 0x25 # Frequency Synthesizer Calibration
|
||||
self.CC1101_FSCAL0 = 0x26 # Frequency Synthesizer Calibration
|
||||
self.CC1101_RCCTRL1 = 0x27 # RC Oscillator Configuration
|
||||
self.CC1101_RCCTRL0 = 0x28 # RC Oscillator Configuration
|
||||
self.CC1101_FSTEST = 0x29 # Frequency Synthesizer Calibration Control
|
||||
self.CC1101_PTEST = 0x2A # Production Test
|
||||
self.CC1101_AGCTEST = 0x2B # AGC Test
|
||||
self.CC1101_TEST2 = 0x2C # Various Test Settings
|
||||
self.CC1101_TEST1 = 0x2D # Various Test Settings
|
||||
self.CC1101_TEST0 = 0x2E # Various Test Settings
|
||||
|
||||
# CC1101 Status Registers.
|
||||
self.CC1101_PARTNUM = 0x30 # Chip ID
|
||||
self.CC1101_VERSION = 0x31 # Chip ID
|
||||
self.CC1101_FREQEST = 0x32 # Frequency Offset Estimate from Demodulator
|
||||
self.CC1101_LQI = 0x33 # Demodulator Estimate for Link Quality
|
||||
self.CC1101_RSSI = 0x34 # Received Signal Strength Indication
|
||||
self.CC1101_MARCSTATE = 0x35 # Main Radio Control State Machine State
|
||||
self.CC1101_WORTIME1 = 0x36 # High Byte of WOR Time
|
||||
self.CC1101_WORTIME0 = 0x37 # Low Byte of WOR Time
|
||||
self.CC1101_PKTSTATUS = 0x38 # Current GDOx Status and Packet Status
|
||||
self.CC1101_VCO_VC_DAC = 0x39 # Current Setting from PLL Calibration Module
|
||||
self.CC1101_TXBYTES = 0x3A # Underflow and Number of Bytes
|
||||
self.CC1101_RXBYTES = 0x3B # Overflow and Number of Bytes
|
||||
self.CC1101_RCCTRL1_STATUS = 0x3C # Last RC Oscillator Calibration Result
|
||||
self.CC1101_RCCTRL0_STATUS = 0x3D # Last RC Oscillator Calibration Result
|
||||
|
||||
# CC1101 PA Table, TX FIFO and RX FIFO.
|
||||
self.CC1101_PATABLE = 0x3E # PA TABLE address
|
||||
self.CC1101_TXFIFO = 0x3F # TX FIFO address
|
||||
self.CC1101_RXFIFO = 0x3F # RX FIFO address
|
||||
|
||||
# CC1101 Command Strobes.
|
||||
self.CC1101_SRES = 0x30 # Reset CC1101 chip
|
||||
self.CC1101_SFSTXON = 0x31 # Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL = 1). If in RX (with CCA):
|
||||
# Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
|
||||
self.CC1101_SXOFF = 0x32 # Turn off crystal oscillator
|
||||
self.CC1101_SCAL = 0x33 # Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without
|
||||
# setting manual calibration mode (MCSM0.FS_AUTOCAL = 0)
|
||||
self.CC1101_SRX = 0x34 # Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL = 1
|
||||
self.CC1101_STX = 0x35 # In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL = 1.
|
||||
# If in RX state and CCA is enabled: Only go to TX if channel is clear
|
||||
self.CC1101_SIDLE = 0x36 # Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable
|
||||
self.CC1101_SWOR = 0x38 # Start automatic RX polling sequence (Wake-on-Radio) if WORCTRL.RC_PD = 0
|
||||
self.CC1101_SPWD = 0x39 # Enter power down mode when CSn goes high
|
||||
self.CC1101_SFRX = 0x3A # Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
|
||||
self.CC1101_SFTX = 0x3B # Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
|
||||
self.CC1101_SWORRST = 0x3C # Reset real time clock to Event1 value
|
||||
self.CC1101_SNOP = 0x3D # No operation. May be used to get access to the chip status byte
|
||||
|
||||
# CC1101 Transfer Types.
|
||||
self.WRITE_BURST = 0x40
|
||||
self.READ_SINGLE = 0x80
|
||||
self.READ_BURST = 0xC0
|
||||
|
||||
# CC1101 Returned Status Bytes.
|
||||
self.CC1101_STATE_IDLE = 0x01
|
||||
self.CC1101_STATE_ENDCAL = 0x0C
|
||||
self.CC1101_STATE_RX = 0x0D
|
||||
self.CC1101_STATE_RXFIFO_ERROR = 0x11
|
||||
self.CC1101_STATE_TX = 0x13
|
||||
self.CC1101_STATE_TX_END = 0x14
|
||||
self.CC1101_STATE_TXFIFO_ERROR = 0x16
|
||||
self.reset()
|
||||
self.setRegisters()
|
||||
for i in range(0, 5):
|
||||
self.freqComp[i] = self.DAVIS_FSCTRL0
|
||||
|
||||
def readRegister(self, regAddr):
|
||||
addr = regAddr | self.READ_SINGLE
|
||||
ss.off()
|
||||
read_addr = bytes([addr])
|
||||
self.hspi.write(read_addr)
|
||||
val = self.hspi.read(1, 0x00)
|
||||
ss.on()
|
||||
return int(val[0])
|
||||
|
||||
def writeRegister(self, regAddr, value):
|
||||
ss.off()
|
||||
self.hspi.write(bytes([regAddr]))
|
||||
self.hspi.write(bytes([value]))
|
||||
ss.on()
|
||||
|
||||
def writeBurst(self, regAddr, wr_buffer):
|
||||
addr = regAddr | self.WRITE_BURST
|
||||
ss.off()
|
||||
self.hspi.write(bytes([addr]))
|
||||
for contents in wr_buffer:
|
||||
self.hspi.write(bytes([contents]))
|
||||
ss.on()
|
||||
|
||||
def readBurst(self, regAddr, size):
|
||||
addr = regAddr | self.READ_BURST
|
||||
ss.off()
|
||||
self.hspi.write(bytes([addr]))
|
||||
rd_buffer = []
|
||||
for i in range(0, size):
|
||||
rd_result = self.hspi.read(1, 0x00)
|
||||
rd_buffer.append(hex(rd_result[0]))
|
||||
ss.on()
|
||||
return rd_buffer
|
||||
|
||||
def cmdStrobe(self, command):
|
||||
ss.off()
|
||||
self.hspi.write(bytes([command]))
|
||||
ss.on()
|
||||
|
||||
def readStatus(self, regAddr):
|
||||
addr = regAddr | self.READ_BURST
|
||||
ss.off()
|
||||
self.hspi.write(bytes([addr]))
|
||||
value = self.hspi.read(1, 0x00)
|
||||
ss.on()
|
||||
return int(value[0])
|
||||
|
||||
def reset(self):
|
||||
ss.off()
|
||||
utime.sleep_ms(1)
|
||||
ss.on()
|
||||
utime.sleep_ms(1)
|
||||
ss.off()
|
||||
while so.value():
|
||||
pass
|
||||
self.hspi.write(bytes([self.CC1101_SRES]))
|
||||
while so.value():
|
||||
pass
|
||||
ss.on()
|
||||
|
||||
def sidle(self):
|
||||
self.cmdStrobe(self.CC1101_SIDLE)
|
||||
while self.readStatus(self.CC1101_MARCSTATE) != 0x01:
|
||||
utime.sleep_us(100)
|
||||
self.cmdStrobe(self.CC1101_SFTX)
|
||||
self.cmdStrobe(self.CC1101_SFRX)
|
||||
utime.sleep_us(100)
|
||||
|
||||
def setRegisters(self):
|
||||
self.writeRegister(self.CC1101_IOCFG2, self.DAVIS_IOCFG2)
|
||||
self.writeRegister(self.CC1101_IOCFG1, self.DAVIS_IOCFG1)
|
||||
self.writeRegister(self.CC1101_IOCFG0, self.DAVIS_IOCFG0)
|
||||
self.writeRegister(self.CC1101_FIFOTHR, self.DAVIS_FIFOTHR)
|
||||
self.writeRegister(self.CC1101_SYNC1, self.DAVIS_SYNC1)
|
||||
self.writeRegister(self.CC1101_SYNC0, self.DAVIS_SYNC0)
|
||||
self.writeRegister(self.CC1101_PKTLEN, self.DAVIS_PKTLEN)
|
||||
self.writeRegister(self.CC1101_PKTCTRL1, self.DAVIS_PKTCTRL1)
|
||||
self.writeRegister(self.CC1101_PKTCTRL0, self.DAVIS_PKTCTRL0)
|
||||
self.writeRegister(self.CC1101_ADDR, self.DAVIS_ADDR)
|
||||
self.writeRegister(self.CC1101_CHANNR, self.DAVIS_CHANNR)
|
||||
self.writeRegister(self.CC1101_FSCTRL1, self.DAVIS_FSCTRL1)
|
||||
self.writeRegister(self.CC1101_FSCTRL0, self.DAVIS_FSCTRL0)
|
||||
self.writeRegister(self.CC1101_FREQ2, self.DAVIS_FREQ2)
|
||||
self.writeRegister(self.CC1101_FREQ1, self.DAVIS_FREQ1)
|
||||
self.writeRegister(self.CC1101_FREQ0, self.DAVIS_FREQ0)
|
||||
self.writeRegister(self.CC1101_MDMCFG4, self.DAVIS_MDMCFG4)
|
||||
self.writeRegister(self.CC1101_MDMCFG3, self.DAVIS_MDMCFG3)
|
||||
self.writeRegister(self.CC1101_MDMCFG2, self.DAVIS_MDMCFG2)
|
||||
self.writeRegister(self.CC1101_MDMCFG1, self.DAVIS_MDMCFG1)
|
||||
self.writeRegister(self.CC1101_MDMCFG0, self.DAVIS_MDMCFG0)
|
||||
self.writeRegister(self.CC1101_DEVIATN, self.DAVIS_DEVIATN)
|
||||
self.writeRegister(self.CC1101_MCSM2, self.DAVIS_MCSM2)
|
||||
self.writeRegister(self.CC1101_MCSM1, self.DAVIS_MCSM1)
|
||||
self.writeRegister(self.CC1101_MCSM0, self.DAVIS_MCSM0)
|
||||
self.writeRegister(self.CC1101_FOCCFG, self.DAVIS_FOCCFG)
|
||||
self.writeRegister(self.CC1101_BSCFG, self.DAVIS_BSCFG)
|
||||
self.writeRegister(self.CC1101_AGCCTRL2, self.DAVIS_AGCCTRL2)
|
||||
self.writeRegister(self.CC1101_AGCCTRL1, self.DAVIS_AGCCTRL1)
|
||||
self.writeRegister(self.CC1101_AGCCTRL0, self.DAVIS_AGCCTRL0)
|
||||
self.writeRegister(self.CC1101_WOREVT1, self.DAVIS_WOREVT1)
|
||||
self.writeRegister(self.CC1101_WOREVT0, self.DAVIS_WOREVT0)
|
||||
self.writeRegister(self.CC1101_WORCTRL, self.DAVIS_WORCTRL)
|
||||
self.writeRegister(self.CC1101_FREND1, self.DAVIS_FREND1)
|
||||
self.writeRegister(self.CC1101_FREND0, self.DAVIS_FREND0)
|
||||
self.writeRegister(self.CC1101_FSCAL3, self.DAVIS_FSCAL3)
|
||||
self.writeRegister(self.CC1101_FSCAL2, self.DAVIS_FSCAL2)
|
||||
self.writeRegister(self.CC1101_FSCAL1, self.DAVIS_FSCAL1)
|
||||
self.writeRegister(self.CC1101_FSCAL0, self.DAVIS_FSCAL0)
|
||||
self.writeRegister(self.CC1101_RCCTRL1, self.DAVIS_RCCTRL1)
|
||||
self.writeRegister(self.CC1101_RCCTRL0, self.DAVIS_RCCTRL0)
|
||||
self.writeRegister(self.CC1101_FSTEST, self.DAVIS_FSTEST)
|
||||
self.writeRegister(self.CC1101_PTEST, self.DAVIS_PTEST)
|
||||
self.writeRegister(self.CC1101_AGCTEST, self.DAVIS_AGCTEST)
|
||||
self.writeRegister(self.CC1101_TEST2, self.DAVIS_TEST2)
|
||||
self.writeRegister(self.CC1101_TEST1, self.DAVIS_TEST1)
|
||||
self.writeRegister(self.CC1101_TEST0, self.DAVIS_TEST0)
|
||||
self.writeBurst(self.CC1101_PATABLE, self.PA_TABLE)
|
||||
self.setFrequency(self.hopIndex)
|
||||
|
||||
def flush(self):
|
||||
self.sidle()
|
||||
self.cmdStrobe(self.CC1101_SFRX) # Flush Rx FIFO
|
||||
self.cmdStrobe(self.CC1101_SFTX) # Flush Tx FIFO
|
||||
self.rxBuffer = [0x00] * self.BUFFER_SIZE
|
||||
self.rxBufferLength = self.rxBufferIndex = 0
|
||||
|
||||
def rx(self):
|
||||
self.cmdStrobe(self.CC1101_SRX)
|
||||
while (self.readStatus(self.CC1101_MARCSTATE) & 0x1F) != self.CC1101_STATE_RX:
|
||||
utime.sleep_us(900)
|
||||
self.rxing = 1
|
||||
self.writeRegister(self.CC1101_IOCFG0, self.DAVIS_IOCFG0)
|
||||
|
||||
def hop(self):
|
||||
self.hopIndex += 1 # Increment the index
|
||||
if (self.hopIndex > 4): # 5 EU frequencies
|
||||
self.hopIndex = 0
|
||||
self.writeRegister(self.CC1101_FSCTRL0, self.freqComp[self.hopIndex])
|
||||
self.setFrequency(self.hopIndex) # Set the frequency.
|
||||
|
||||
def setFrequency(self, index):
|
||||
self.sidle()
|
||||
self.writeRegister(self.CC1101_FREQ2, self.FREQ_2[index])
|
||||
self.writeRegister(self.CC1101_FREQ1, self.FREQ_1[index])
|
||||
self.writeRegister(self.CC1101_FREQ0, self.FREQ_0[index])
|
||||
self.flush()
|
||||
|
||||
def calcCrc(self, _buffer, length):
|
||||
crc = 0x0000
|
||||
buffer_index = 0
|
||||
for i in range(length, 0, -1):
|
||||
crc = (crc << 8) ^ self.CRC_TABLE[(crc >> 8) ^ (_buffer[buffer_index])]
|
||||
buffer_index += 1
|
||||
return crc
|
||||
|
||||
def readRssi(self):
|
||||
rssi = self.readRegister(self.CC1101_RXFIFO)
|
||||
if rssi >= 128:
|
||||
return (rssi - 256)/2 - 74
|
||||
elif rssi < 128:
|
||||
return rssi/2 -74
|
||||
else:
|
||||
return False
|
||||
|
||||
def readLQI(self):
|
||||
return self.readRegister(self.CC1101_RXFIFO) & 0x7F
|
||||
|
||||
BIN
davis_decode.mpy
Normal file
BIN
davis_decode.mpy
Normal file
Binary file not shown.
223
davis_decode.py
Normal file
223
davis_decode.py
Normal file
@@ -0,0 +1,223 @@
|
||||
import urequests
|
||||
|
||||
|
||||
_DEBUG = False
|
||||
|
||||
|
||||
def send_to_influx(host, port, db, user, password, davis_unit_id, wind, measurement, name, value, tags):
|
||||
post = "http://{}:{}/write?db={}".format(host, port, db)
|
||||
if _DEBUG:
|
||||
print("SENDING TO: {}".format(post))
|
||||
if measurement is False:
|
||||
return (False, "ERROR measurement set False")
|
||||
if measurement is None:
|
||||
data = "wind,type=speed,davis_id={_davis_id} value={_speed}\n wind,type=direction,davis_id={_davis_id} value={_direction}".format(
|
||||
_davis_id = davis_unit_id,
|
||||
_speed=wind['speed'],
|
||||
_direction=wind['direction'])
|
||||
if _DEBUG:
|
||||
print("SEND WIND only: {}")
|
||||
else:
|
||||
for tag in tags.keys():
|
||||
measurement = "{},{}={}".format(measurement, tag, tags[tag])
|
||||
data = "{_measure},davis_id={_davis_id} {_name}={_value}\n wind,type=speed,davis_id={_davis_id} value={_speed}\n wind,type=direction,davis_id={_davis_id} value={_direction}".format(
|
||||
_measure=measurement,
|
||||
_name=name,
|
||||
_value=value,
|
||||
_davis_id = davis_unit_id,
|
||||
_speed=wind['speed'],
|
||||
_direction=wind['direction'])
|
||||
if _DEBUG:
|
||||
print("POST_DATA: {}".format(data))
|
||||
try:
|
||||
return (True, urequests.post(post, data=data))
|
||||
except Exception as e:
|
||||
return (False, "ERROR sending data to influx: {}".format(e))
|
||||
|
||||
|
||||
def reverseBits(data):
|
||||
data = "{:08b}".format(data)
|
||||
z = ""
|
||||
for i in range(len(data),0,-1):
|
||||
z = z + (data[i-1])
|
||||
return int(z, 2)
|
||||
|
||||
|
||||
class davisDecoder(object):
|
||||
def __init__(self, weather_db, stat_db, raw_db):
|
||||
__name__ = u'Davis value decoder class'
|
||||
self.weather_influx_db = weather_db
|
||||
self.stat_influx_db = stat_db
|
||||
self.raw_influx_db = raw_db
|
||||
|
||||
def byte_split(self, data):
|
||||
msb = data >> 4
|
||||
lsb = data & 0b00001111
|
||||
result = {"MSB": msb, "LSB": lsb}
|
||||
return result
|
||||
|
||||
def davis_id(self, header):
|
||||
self.davis_packet_id = 0
|
||||
self.battery_low = 0
|
||||
self.unit_id = 0
|
||||
bin_header = self.byte_split(header)
|
||||
self.unit_id = bin_header['LSB'] & 0b0111
|
||||
self.battery_low = bin_header['LSB'] >> 3
|
||||
self.davis_packet_id = bin_header['MSB']
|
||||
result = {"davis_id": self.unit_id,
|
||||
"packet_id": self.davis_packet_id,
|
||||
"bat_low": self.battery_low}
|
||||
return result
|
||||
|
||||
def decode_wind(self, databytes):
|
||||
# wind speed in mph, i suppose. Let's convert it
|
||||
wind_speed = round(float(databytes['windspeed'] * 1.60934), 1)
|
||||
wind_direction_factor = round(float(360)/float(255), 1)
|
||||
wind_direction = databytes['winddir']
|
||||
wind_direction = float(wind_direction) * wind_direction_factor
|
||||
result = {"speed": wind_speed, "direction": wind_direction}
|
||||
return result
|
||||
|
||||
def decode_temp(self, temp):
|
||||
temp_f = (float(temp)) / float(160) # in Fahrenheit
|
||||
temp_c = round((temp_f - 32) * float(5)/float(9), 1)
|
||||
result = {"celsius": temp_c, "fahrenheit": temp_f}
|
||||
return result
|
||||
|
||||
def decode_humidity(self, hum):
|
||||
pass
|
||||
|
||||
def supercap_decode(self, byte2, byte3):
|
||||
cap = (byte2 << 2) + (byte3 >> 6)
|
||||
result = float(cap / 100.00)
|
||||
return result
|
||||
|
||||
def solarvolt_decode(self, byte2, byte3):
|
||||
solar = (byte2 << 1) + (byte3 >> 7)
|
||||
result = float(solar)
|
||||
return result
|
||||
|
||||
def rain_decode(self, rain):
|
||||
result = float(rain & 0x7F)
|
||||
return result
|
||||
|
||||
def rainrate_decode(self, byte2, byte3):
|
||||
# if byte3(b2 here) is 0xFF, or 255, there is no rain
|
||||
#print("b2:{} b3:{} = result:{}".format(byte2, byte3, byte2 + (byte3 >> 4 << 8)))
|
||||
if byte2 == 255:
|
||||
rainstate = 0
|
||||
rainrate = 0
|
||||
elif byte2 == 254:
|
||||
rainstate = 1
|
||||
rainrate = 0.2
|
||||
else:
|
||||
rainstate = 2
|
||||
if byte3 > 4:
|
||||
rainrate = 720 / ((byte3 >> 4 << 8) + byte2)
|
||||
else:
|
||||
rainrate = 0
|
||||
result = {"state": float(rainstate), "rate": float(rainrate)}
|
||||
#print(result)
|
||||
return result
|
||||
|
||||
def DecodePacket(self, packet):
|
||||
# By default and most of the time, write to weather
|
||||
self.write_influx_db = self.weather_influx_db
|
||||
# Set all to None
|
||||
self.wind = False
|
||||
self.measurement = False
|
||||
self.name = False
|
||||
self.value = False
|
||||
self.tags = False
|
||||
self.wind = self.decode_wind(
|
||||
{"windspeed": packet[1], "winddir": packet[2]})
|
||||
if self.davis_packet_id == 2:
|
||||
# SuperCap charge 0x2
|
||||
if _DEBUG:
|
||||
print('SCAP:')
|
||||
supercap = self.supercap_decode(
|
||||
packet[3], packet[4]
|
||||
)
|
||||
if _DEBUG:
|
||||
print("{}".format(supercap))
|
||||
self.write_influx_db = self.stat_influx_db
|
||||
self.measurement = 'iss'
|
||||
self.name = 'voltage'
|
||||
self.tags = {'type': 'capacitor'}
|
||||
self.value = supercap
|
||||
elif self.davis_packet_id == 3:
|
||||
# No fucking idea 0x3
|
||||
# {'hop':1,'h':48,'b0':6,'b1':237,'b2':255,'b3':195,'b4':135,'b5':50,'b6':110,'b7':255,'b8':255,'b9':179,'rssi':45,'lqi':0,'nxt':64,'cnt':163}
|
||||
self.measurement = None
|
||||
self.name = None
|
||||
self.tags = None
|
||||
self.value = None
|
||||
|
||||
elif self.davis_packet_id == 5:
|
||||
# Rainrate 0x5
|
||||
rainrate_dict = self.rainrate_decode(
|
||||
packet[3],
|
||||
packet[4])
|
||||
if _DEBUG:
|
||||
print("RAINRATE: {}".format(rainrate_dict))
|
||||
self.measurement = 'rain'
|
||||
self.name = 'value'
|
||||
self.tags = {'type': 'rainrate'}
|
||||
self.value = rainrate_dict['rate']
|
||||
elif self.davis_packet_id == 6:
|
||||
# Sun Irradiation 0x6 (NOT ON vantage Vue)
|
||||
pass
|
||||
elif self.davis_packet_id == 7:
|
||||
# Super Cap voltage 0x7
|
||||
solarvolt = self.solarvolt_decode(
|
||||
packet[3], packet[4]
|
||||
)
|
||||
if _DEBUG:
|
||||
print("SOLV {}".format(solarvolt))
|
||||
self.write_influx_db = self.stat_influx_db
|
||||
self.measurement = 'iss'
|
||||
self.name = 'voltage'
|
||||
self.tags = {'type': 'solar'}
|
||||
self.value = solarvolt
|
||||
elif self.davis_packet_id == 8:
|
||||
# Temperature 0x8
|
||||
raw_temp = (packet[3] << 8) + packet[4]
|
||||
temp_dict = self.decode_temp(raw_temp)
|
||||
temp = float(temp_dict['celsius'])
|
||||
if _DEBUG:
|
||||
print("TEMP: {}".format(temp))
|
||||
self.measurement = 'temphumi'
|
||||
self.name = 'temperature'
|
||||
self.tags = {'type': 'external'}
|
||||
self.value = temp
|
||||
elif self.davis_packet_id == 9:
|
||||
# Wind gusts 0x9
|
||||
windgust = packet[3] * 1.60934
|
||||
if _DEBUG:
|
||||
print("WINDGUST: {}".format(windgust))
|
||||
self.measurement = 'wind'
|
||||
self.name = 'value'
|
||||
self.tags = {'type': 'windgust'}
|
||||
self.value = windgust
|
||||
elif self.davis_packet_id == 10:
|
||||
# Humidity 0xa
|
||||
raw_humidity = (((packet[4] >> 4) & 0b0011) << 8) \
|
||||
+ packet[3]
|
||||
humidity = round(int(raw_humidity) / float(10), 1)
|
||||
if _DEBUG:
|
||||
print("HUMI: {}".format(humidity))
|
||||
self.measurement = 'temphumi'
|
||||
self.name = 'humidity'
|
||||
self.tags = {'type': 'external'}
|
||||
self.value = humidity
|
||||
elif self.davis_packet_id == 14:
|
||||
# Rain bucket tips 0xe
|
||||
raw_rain = (packet[3]) + (packet[4] >> 7 << 8)
|
||||
rain = self.rain_decode(raw_rain)
|
||||
if _DEBUG:
|
||||
print("RAINCOUNT: {}".format(rain))
|
||||
self.measurement = 'rain'
|
||||
self.name = 'value'
|
||||
self.tags = {'type': 'rain_bucket_tips'}
|
||||
self.value = rain
|
||||
|
||||
20
inet.conf
Normal file
20
inet.conf
Normal file
@@ -0,0 +1,20 @@
|
||||
# No spaces around '='
|
||||
# Try to avoid spaced at end or beginning of passwords. Stripping it
|
||||
# One config option per line, all options need to be set.
|
||||
|
||||
_SSID=YourSSID
|
||||
_PASS=YourWifiPass
|
||||
|
||||
# Time to keep waiting for the network to come up. Delay is 1001ms
|
||||
_TIMEOUT=15
|
||||
_INFLUX_HOST=IPofTheInfluxDB
|
||||
_INFLUX_PORT=PortOfTheInfluxDB
|
||||
|
||||
# currently not implemented
|
||||
_INFLUX_USER=InfluxUser
|
||||
_INFLUX_PASS=HisPasswd
|
||||
|
||||
# Names of the databases
|
||||
_INF_DB_WEATHER=weather
|
||||
_INF_DB_STATUS=status
|
||||
_INF_DB_RAW=raw
|
||||
158
influx_structure.md
Normal file
158
influx_structure.md
Normal file
@@ -0,0 +1,158 @@
|
||||
#Structure of InfluxDB
|
||||
InfluxDB was chosen for it's simplicity and ease of management, live with it.
|
||||
|
||||
##influxDB SCHEMA:
|
||||
Firs off, 2 databases:
|
||||
weather
|
||||
status
|
||||
|
||||
###DB weather
|
||||
measure wind
|
||||
----------------
|
||||
value | speed or direction or windgust | davis_id
|
||||
---------------------------------------------------
|
||||
field tag tag
|
||||
|
||||
measure temphumi
|
||||
----------------
|
||||
temperature | humidity | external, internal | davis_id
|
||||
---------------------------------------------------------
|
||||
field field tag tag
|
||||
|
||||
measure rain
|
||||
----------------
|
||||
rain | rate / total / intensity | davis_id
|
||||
---------------------------------------------
|
||||
field tag tag
|
||||
|
||||
|
||||
|
||||
###DB status
|
||||
|
||||
iss measure
|
||||
----------------
|
||||
voltage | solar or capacitor
|
||||
----------------------------------------------------------------
|
||||
field tag
|
||||
|
||||
RasPI system (only on the raspi system)
|
||||
----------------
|
||||
usage | disk, mem, cpu, eth, wifi %
|
||||
------------------------------------
|
||||
field | tag
|
||||
|
||||
## Retention policies
|
||||
-------
|
||||
weather
|
||||
-------
|
||||
create retention policy realtime on weather duration 168h replication 1 shard duration 1h
|
||||
create retention policy monthly on weather duration 720h replication 1 shard duration 24h
|
||||
create retention policy yearly on weather duration 8760h replication 1 shard duration 168h
|
||||
create retention policy infinite on weather duration 0s replication 1 shard duration 720h
|
||||
alter retention policy realtime on weather default
|
||||
|
||||
------
|
||||
status
|
||||
------
|
||||
create retention policy realtime on status duration 168h replication 1 shard duration 1h
|
||||
create retention policy monthly on status duration 720h replication 1 shard duration 24h
|
||||
create retention policy yearly on status duration 8760h replication 1 shard duration 168h
|
||||
create retention policy infinite on status duration 0s replication 1 shard duration 720h
|
||||
alter retention policy realtime on status default
|
||||
|
||||
## Continuous queries
|
||||
-------------------------------------------------------------------------------
|
||||
WIND
|
||||
-------------------------------------------------------------------------------
|
||||
CREATE CONTINUOUS QUERY "cq_wind_10m" ON "weather_v2" BEGIN
|
||||
SELECT max(value) AS wind_max, mean(value) AS wind, min(value) AS wind_min
|
||||
INTO "monthly"."wind_aggregated"
|
||||
FROM realtime.wind
|
||||
GROUP BY time(10m), type
|
||||
END
|
||||
CREATE CONTINUOUS QUERY "cq_wind_1h" ON "weather_v2" BEGIN
|
||||
SELECT max(value) AS wind_max, mean(value) AS wind, min(value) AS wind_min
|
||||
INTO "yearly"."wind_aggregated"
|
||||
FROM realtime.wind
|
||||
GROUP BY time(1h), type
|
||||
END
|
||||
CREATE CONTINUOUS QUERY "cq_wind_6h" ON "weather_v2" BEGIN
|
||||
SELECT max(value) AS wind_max, mean(value) AS wind, min(value) AS wind_min
|
||||
INTO "infinite"."wind_aggregated"
|
||||
FROM realtime.wind
|
||||
GROUP BY time(6h), type
|
||||
END
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
RAIN
|
||||
-------------------------------------------------------------------------------
|
||||
CREATE CONTINUOUS QUERY "cq_rain_10m" ON "weather_v2" BEGIN
|
||||
SELECT max("value") AS val_max, mean(value) AS value
|
||||
INTO "monthly"."rainrate_aggregated"
|
||||
FROM realtime.rain
|
||||
GROUP BY type,time(10m)
|
||||
END
|
||||
CREATE CONTINUOUS QUERY "cq_rain_1h" ON "weather_v2" BEGIN
|
||||
SELECT max("value") AS val_max, mean(value) AS value
|
||||
INTO "yearly"."rainrate_aggregated"
|
||||
FROM realtime.rain
|
||||
GROUP BY type,time(1h)
|
||||
END
|
||||
CREATE CONTINUOUS QUERY "cq_rain_6h" ON "weather_v2" BEGIN
|
||||
SELECT max("value") AS val_max, mean(value) AS value
|
||||
INTO "infinite"."rainrate_aggregated"
|
||||
FROM realtime.rain
|
||||
GROUP BY type,time(6h)
|
||||
END
|
||||
-------------------------------------------------------------------------------
|
||||
TEMPHUMI
|
||||
-------------------------------------------------------------------------------
|
||||
CREATE CONTINUOUS QUERY "cq_temphumi_10m" ON "weather_v2" BEGIN
|
||||
SELECT
|
||||
max("humidity") AS humidity_max,
|
||||
min("humidity") AS humidity_min,
|
||||
mean("humidity") AS humidity,
|
||||
max("temperature") AS temperature_max,
|
||||
min("temperature") AS temperature_min,
|
||||
mean("temperature") AS temperature
|
||||
INTO "monthly"."temphumi_aggregated"
|
||||
FROM realtime.temphumi
|
||||
GROUP BY type, time(10m)
|
||||
END
|
||||
|
||||
CREATE CONTINUOUS QUERY "cq_temphumi_1h" ON "weather_v2" BEGIN
|
||||
SELECT
|
||||
max("humidity") AS humidity_max,
|
||||
min("humidity") AS humidity_min,
|
||||
mean("humidity") AS humidity,
|
||||
max("temperature") AS temperature_max,
|
||||
min("temperature") AS temperature_min,
|
||||
mean("temperature") AS temperature
|
||||
INTO "yearly"."temphumi_aggregated"
|
||||
FROM realtime.temphumi
|
||||
GROUP BY type, time(1h)
|
||||
END
|
||||
|
||||
CREATE CONTINUOUS QUERY "cq_temphumi_6h" ON "weather_v2" BEGIN
|
||||
SELECT
|
||||
max("humidity") AS humidity_max,
|
||||
min("humidity") AS humidity_min,
|
||||
mean("humidity") AS humidity,
|
||||
max("temperature") AS temperature_max,
|
||||
min("temperature") AS temperature_min,
|
||||
mean("temperature") AS temperature
|
||||
INTO "infinite"."temphumi_aggregated"
|
||||
FROM realtime.temphumi
|
||||
GROUP BY type, time(6h)
|
||||
END
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
TRAFFIC
|
||||
-------------------------------------------------------------------------------
|
||||
CREATE CONTINUOUS QUERY "cq_net_1m" ON "status" BEGIN
|
||||
SELECT NON_NEGATIVE_DERIVATIVE(max(*)) as traffic
|
||||
INTO "monthly"."net_aggregated"
|
||||
FROM realtime.net
|
||||
WHERE time > now()-1m
|
||||
GROUP BY time(30s)
|
||||
END
|
||||
89
main.py
Normal file
89
main.py
Normal file
@@ -0,0 +1,89 @@
|
||||
import cc1101_davis
|
||||
import davis_decode
|
||||
import utime
|
||||
import WiFi
|
||||
gc.collect()
|
||||
|
||||
_DEBUG = False
|
||||
|
||||
wifi_con = WiFi.NetSet('infra')
|
||||
wifi_con.readNetworkConfig()
|
||||
ips = wifi_con.connectInfra(
|
||||
wifi_con._SSID,
|
||||
wifi_con._PASS,
|
||||
wifi_con._TIMEOUT)
|
||||
|
||||
if _DEBUG:
|
||||
print("IPCONF: {}".format(ips))
|
||||
|
||||
davis = cc1101_davis.CC1101()
|
||||
davis.setRegisters()
|
||||
davis.setFrequency(davis.hopIndex)
|
||||
decoder = davis_decode.davisDecoder(
|
||||
wifi_con._INF_DB_WEATHER,
|
||||
wifi_con._INF_DB_STATUS,
|
||||
wifi_con._INF_DB_RAW)
|
||||
|
||||
# Main receive loop
|
||||
while True:
|
||||
data_length = davis.readRegister(davis.CC1101_RXBYTES)
|
||||
data = ""
|
||||
if data_length & 0x7f == 15:
|
||||
data = davis.readBurst(davis.CC1101_RXFIFO, 10)
|
||||
rssi = davis.readRssi()
|
||||
lqi = davis.readLQI()
|
||||
hop = davis.hopIndex
|
||||
davis.flush()
|
||||
davis.hop()
|
||||
davis.rx()
|
||||
data_int = [davis_decode.reverseBits(int(item)) for item in data]
|
||||
header = decoder.davis_id(data_int[0])
|
||||
decoder.DecodePacket(data_int)
|
||||
data_prn = "{:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5} {:5}".format(
|
||||
data_int[0],
|
||||
data_int[1],
|
||||
data_int[2],
|
||||
data_int[3],
|
||||
data_int[4],
|
||||
data_int[5],
|
||||
data_int[6],
|
||||
data_int[7],
|
||||
data_int[8],
|
||||
data_int[8],)
|
||||
print("{_data:60} HOP: {_hop:<5} RSSI: {_rssi:<5} LQI: {_lqi:<5}".format(
|
||||
_rssi=rssi,
|
||||
_hop=hop,
|
||||
_data=data_prn,
|
||||
_lqi=lqi))
|
||||
if _DEBUG:
|
||||
print("Header: {} Wind: {}".format(header, decoder.wind))
|
||||
print("{}: {}/{} ({})".format(
|
||||
decoder.measurement,
|
||||
decoder.name,
|
||||
decoder.value,
|
||||
decoder.tags))
|
||||
sent_ok = False
|
||||
data_sent = None
|
||||
try:
|
||||
(sent_ok, data_sent) = davis_decode.send_to_influx(
|
||||
wifi_con._INFLUX_HOST,
|
||||
wifi_con._INFLUX_PORT,
|
||||
decoder.write_influx_db,
|
||||
wifi_con._INFLUX_USER,
|
||||
wifi_con._INFLUX_PASS,
|
||||
decoder.unit_id,
|
||||
decoder.wind,
|
||||
decoder.measurement,
|
||||
decoder.name,
|
||||
decoder.value,
|
||||
decoder.tags)
|
||||
except Exception as e:
|
||||
print("ERROR: Data send 'urequest': {}".format(e))
|
||||
if _DEBUG:
|
||||
if sent_ok:
|
||||
print("DATA SEND: {}".format(data_sent.status_code))
|
||||
else:
|
||||
print("DATA SEND FAIL: {}".format(data_sent))
|
||||
else:
|
||||
utime.sleep_ms(100)
|
||||
gc.collect()
|
||||
371
readme.md
Normal file
371
readme.md
Normal file
@@ -0,0 +1,371 @@
|
||||
#ESP8266 + CC1101 Davis weather station wifi logger
|
||||
|
||||
|
||||
The intention is to gather data from a Weather station made by Davis.
|
||||
In this case a Vantage Vue (integrated all sensors in one package) and
|
||||
push them directly to an InfluxDB instance via WiFi.
|
||||
|
||||
##Prerequisites:
|
||||
- WiFi available, plus access to it. (WPA2 PSK preferred)
|
||||
- Running INfluxDB instance on the same network
|
||||
- ESP8266 microcontroller (NodeMCU 8266 preferred)
|
||||
- git, since you're here, I assume this is already settled
|
||||
- Micropython tools: ampy, esptool
|
||||
- serial console emulator, I use picocom
|
||||
- CC1101 from Texas Instruments radio chip, the 868 MHz version! There are 433Mhz sold out there, read descriptions
|
||||
- a couple wires, need to solder those tiny CC1101 pins and wires.
|
||||
- 5V / 3.3V source, depending on what version of ESP you get. A stable 3.3V is preferred
|
||||
|
||||
##Quick setup of HW:
|
||||
###1. Interconnect these pins:
|
||||
The pins are marked on the NodeMcu ESP8266, on the CC1101 module, pins are counted from left, if you face the chip towards you.
|
||||
|
||||
ESP8266 | ESP8266 description | CC1101 | CC1101 description |
|
||||
|-------|---------------------|-----------|--------------------|
|
||||
|GND | GND | 1- GND | GND |
|
||||
|3V3 | Voltage In | 2- VCC | Vcc, Input voltage |
|
||||
|D7 | GPIO13 | 3- Pin3 | MOSI |
|
||||
|D5 | GPIO14 | 4- Pin4 | SCLK |
|
||||
|D6 | GPIO12 | 5- Pin5 | MISO |
|
||||
|- | - | 6- Pin6 | GDO2 |
|
||||
|- | - | 7- Pin7 | GDO0 |
|
||||
|D8 | GPIO15 | 8- Pin8 | CSN |
|
||||
|
||||
IO pin GDO0, currently configured as interrupt, when new packet is received (i.e. goes HIGH).
|
||||
This currently just to lights up a led, interrupt based receive is not implemented, though sounds cool.
|
||||
|
||||
###2. Clone this repo, get Micropython
|
||||
```
|
||||
git clone https://bastart.spoton.cz/git/Ventil/esp8266_CC1101_davis_vantage_vue.git
|
||||
cd esp8266_CC1101_davis_vantage_vue
|
||||
wget https://micropython.org/resources/firmware/esp8266-20191220-v1.12.bin -P /tmp
|
||||
```
|
||||
###3. Upload Micropython, check
|
||||
Need to delete the flash first, then write the custom firmware.
|
||||
You need to determine which device is the one
|
||||
to write to. If you have only one ESP8266, you are probably safe to use the ttyUSB0,
|
||||
I will use ttyUSB1 as I have multiple UARTS on my machine
|
||||
```
|
||||
esptool.py --port /dev/ttyUSB1 --baud 115200 erase_flash
|
||||
esptool.py v2.8
|
||||
Serial port /dev/ttyUSB1
|
||||
Connecting....
|
||||
Detecting chip type... ESP8266
|
||||
Chip is ESP8266EX
|
||||
Features: WiFi
|
||||
Crystal is 26MHz
|
||||
MAC: cc:50:e3:56:b2:5b
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Erasing flash (this may take a while)...
|
||||
Chip erase completed successfully in 7.8s
|
||||
Hard resetting via RTS pin...
|
||||
```
|
||||
Now it is time to upload uPython:
|
||||
```
|
||||
esptool.py --port /dev/ttyUSB1 --baud 115200 write_flash 0 /tmp/esp8266-20191220-v1.12.bin
|
||||
esptool.py v2.8
|
||||
Serial port /dev/ttyUSB1
|
||||
Connecting....
|
||||
Detecting chip type... ESP8266
|
||||
Chip is ESP8266EX
|
||||
Features: WiFi
|
||||
Crystal is 26MHz
|
||||
MAC: cc:50:e3:56:b2:5b
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Configuring flash size...
|
||||
Auto-detected Flash size: 4MB
|
||||
Flash params set to 0x0040
|
||||
Compressed 619828 bytes to 404070...
|
||||
Wrote 619828 bytes (404070 compressed) at 0x00000000 in 35.8 seconds (effective 138.6 kbit/s)...
|
||||
Hash of data verified.
|
||||
|
||||
Leaving...
|
||||
Hard resetting via RTS pin...
|
||||
```
|
||||
And of course, when you try to get to the serial console, you should get somethinglike this
|
||||
```
|
||||
picocom -b 115200 /dev/ttyUSB1
|
||||
picocom v3.1
|
||||
|
||||
port is : /dev/ttyUSB1
|
||||
flowcontrol : none
|
||||
baudrate is : 115200
|
||||
parity is : none
|
||||
databits are : 8
|
||||
stopbits are : 1
|
||||
escape is : C-a
|
||||
local echo is : no
|
||||
noinit is : no
|
||||
noreset is : no
|
||||
hangup is : no
|
||||
nolock is : no
|
||||
send_cmd is : sz -vv
|
||||
receive_cmd is : rz -vv -E
|
||||
imap is :
|
||||
omap is :
|
||||
emap is : crcrlf,delbs,
|
||||
logfile is : none
|
||||
initstring : none
|
||||
exit_after is : not set
|
||||
exit is : no
|
||||
|
||||
Type [C-a] [C-h] to see available commands
|
||||
Terminal ready
|
||||
|
||||
>>>
|
||||
|
||||
```
|
||||
Exit from the console with Ctrl + A + X or ampy will not be able to list files
|
||||
on the esp8266
|
||||
###4. Freeze modules, or just upload the .mpy files
|
||||
You can simply upload all the modules in question. If you modify anything in the .py
|
||||
files, you need to freeze them again with mpy-cross <filename>
|
||||
```
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put WiFi.mpy
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put cc1101_davis.mpy
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put davis_decode.mpy
|
||||
```
|
||||
|
||||
to freeze a module:
|
||||
```
|
||||
mpy-cross WiFi.py
|
||||
ls -l WiFi.*
|
||||
WiFi.mpy <-- the newly compiled (frozen) module
|
||||
WiFi.py
|
||||
|
||||
```
|
||||
###5. Modify inet.conf
|
||||
Before uploading the inte.conf, please change it to your desired values.
|
||||
###6, Upload files
|
||||
```
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put boot.py
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put main.py
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 put inet.conf
|
||||
|
||||
/usr/bin/ampy -p /dev/ttyUSB1 ls
|
||||
/WiFi.mpy
|
||||
/boot.py
|
||||
/cc1101_davis.mpy
|
||||
/davis_decode.mpy
|
||||
/inet.conf
|
||||
/main.py
|
||||
|
||||
```
|
||||
###7. If you haven't already, create 2 DBs in inclux
|
||||
I am tempted to push the raw, undecoded data to a DB as well, but influx is not siutd for this. You can ignore the last DB creation
|
||||
```
|
||||
ssh 192.168.1.2
|
||||
influx
|
||||
create database weather
|
||||
create database status
|
||||
create database raw
|
||||
```
|
||||
###8. Restart esp8266, check data on serial
|
||||
```
|
||||
picocom -b 115200 /dev/ttyUSB1
|
||||
picocom v3.1
|
||||
|
||||
port is : /dev/ttyUSB1
|
||||
flowcontrol : none
|
||||
baudrate is : 115200
|
||||
parity is : none
|
||||
databits are : 8
|
||||
stopbits are : 1
|
||||
escape is : C-a
|
||||
local echo is : no
|
||||
noinit is : no
|
||||
noreset is : no
|
||||
hangup is : no
|
||||
nolock is : no
|
||||
send_cmd is : sz -vv
|
||||
receive_cmd is : rz -vv -E
|
||||
imap is :
|
||||
omap is :
|
||||
emap is : crcrlf,delbs,
|
||||
logfile is : none
|
||||
initstring : none
|
||||
exit_after is : not set
|
||||
exit is : no
|
||||
|
||||
Type [C-a] [C-h] to see available commands
|
||||
Terminal ready
|
||||
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>>
|
||||
>>> {ll<6C><6C>|<7C>#<23>o
|
||||
|
||||
<20>
|
||||
$<24>
|
||||
c|<7C><><EFBFBD><EFBFBD>|#<23>
|
||||
#<23><>nN<6E>$oN<6F><4E><EFBFBD>
|
||||
bp<62><70>$sl{lp<6C>o<EFBFBD>
|
||||
<20>l
|
||||
|
||||
|
||||
"
|
||||
N<>|<7C>l
|
||||
|
||||
#<23><>nN<6E>$<24><>l`<60>Nl or<6F><72><EFBFBD>N
|
||||
|
||||
<20>
|
||||
<20>$p<>n<EFBFBD>
|
||||
r<>ܜ<EFBFBD>
|
||||
|
||||
bn<62>|$
|
||||
<20><>
|
||||
#<23><>on<6F>
|
||||
l <20>n$<24>$`n{<7B>ےo
|
||||
l <20>o
|
||||
|
||||
<20><>#<23>ol<6F>
|
||||
<20><>no<6E><6F>{lp<6C>o<EFBFBD>
|
||||
|
||||
r<><72><EFBFBD><EFBFBD><EFBFBD>
|
||||
<20>p<EFBFBD>
|
||||
#
|
||||
N<>|<7C><>p<EFBFBD><70>on<6F>l<EFBFBD>l <20>n$<24>$`nr<6E><72><EFBFBD><EFBFBD>
|
||||
$l`{<7B><>n
|
||||
l$ <20><><EFBFBD>o<EFBFBD>r<EFBFBD><72>n|<7C>ll$d`#<23><><EFBFBD>r<EFBFBD>l<EFBFBD>o<EFBFBD><6F>o<EFBFBD>l <20><>r<EFBFBD>$<24>$<24>
|
||||
l`<60><>r<EFBFBD>p<EFBFBD><70>l<EFBFBD>
|
||||
|
||||
$`<60><><EFBFBD>o<EFBFBD>l<EFBFBD><6C><EFBFBD>
|
||||
l$`sl<73><6C>b<EFBFBD><62><EFBFBD>#
|
||||
<20><>B|
|
||||
$b<><62><EFBFBD>#|<7C><><EFBFBD><EFBFBD>l$b<><62>n<EFBFBD><6E>Trying... 15 more times
|
||||
Trying... 14 more times
|
||||
Trying... 13 more times
|
||||
Trying... 12 more times
|
||||
Trying... 11 more times
|
||||
Trying... 10 more times
|
||||
IPCONF: {'ip': '192.168.1.174', 'mask': '255.255.255.0', 'gw': '192.168.1.254', 'dns': '192.168.1.4'}
|
||||
0 10 4 35 8 4 78 196 255 255 HOP: 0 RSSI: -71.5 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 0, 'davis_id': 0} Wind: {'speed': 16.1, 'direction': 5.6}
|
||||
False: False/False (False)
|
||||
DATA SEND FAIL: ERROR measurement set False
|
||||
224 10 234 17 1 4 38 49 255 255 HOP: 1 RSSI: -70 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 14, 'davis_id': 0} Wind: {'speed': 16.1, 'direction': 327.6}
|
||||
rain: value/17.0 ({'type': 'rain_bucket_tips'})
|
||||
DATA SEND: 204
|
||||
80 9 224 255 113 15 89 230 255 255 HOP: 2 RSSI: -70 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 5, 'davis_id': 0} Wind: {'speed': 14.5, 'direction': 313.6}
|
||||
rain: value/0.0 ({'type': 'rainrate'})
|
||||
DATA SEND: 204
|
||||
128 8 252 34 233 10 229 180 255 255 HOP: 3 RSSI: -70 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 8, 'davis_id': 0} Wind: {'speed': 12.9, 'direction': 352.8}
|
||||
temphumi: temperature/13.3 ({'type': 'external'})
|
||||
DATA SEND: 204
|
||||
160 8 249 109 41 2 202 57 255 255 HOP: 4 RSSI: -69 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 10, 'davis_id': 0} Wind: {'speed': 12.9, 'direction': 348.6}
|
||||
temphumi: humidity/62.1 ({'type': 'external'})
|
||||
DATA SEND: 204
|
||||
224 9 225 17 1 2 182 58 255 255 HOP: 0 RSSI: -68 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 14, 'davis_id': 0} Wind: {'speed': 14.5, 'direction': 315.0}
|
||||
rain: value/17.0 ({'type': 'rain_bucket_tips'})
|
||||
DATA SEND: 204
|
||||
80 10 241 255 115 10 236 224 255 255 HOP: 1 RSSI: -68.5 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 5, 'davis_id': 0} Wind: {'speed': 16.1, 'direction': 337.4}
|
||||
rain: value/0.0 ({'type': 'rainrate'})
|
||||
DATA SEND: 204
|
||||
128 16 233 34 219 10 39 214 255 255 HOP: 2 RSSI: -68.5 LQI: 127
|
||||
Header: {'bat_low': 0, 'packet_id': 8, 'davis_id': 0} Wind: {'speed': 25.7, 'direction': 326.2}
|
||||
temphumi: temperature/13.2 ({'type': 'external'})
|
||||
```
|
||||
And with '_DEBUG' set to False on line 7, in main.py:
|
||||
You can see the raw data that are comming in from the Davis weather station.
|
||||
|
||||
```
|
||||
>>>
|
||||
MPY: soft reboot
|
||||
Trying... 15 more times
|
||||
0 17 244 212 193 138 98 76 255 255 HOP: 0 RSSI: -68 LQI: 127
|
||||
224 13 3 17 3 3 32 253 255 255 HOP: 1 RSSI: -68.5 LQI: 127
|
||||
80 13 5 255 112 2 10 211 255 255 HOP: 2 RSSI: -68 LQI: 127
|
||||
128 9 236 34 203 2 181 206 255 255 HOP: 3 RSSI: -68.5 LQI: 127
|
||||
160 11 252 106 43 2 123 92 255 255 HOP: 4 RSSI: -69 LQI: 127
|
||||
224 13 247 17 3 6 37 228 255 255 HOP: 0 RSSI: -68.5 LQI: 127
|
||||
80 12 6 255 113 2 8 111 255 255 HOP: 1 RSSI: -69 LQI: 127
|
||||
128 9 239 34 203 3 62 51 255 255 HOP: 2 RSSI: -70 LQI: 127
|
||||
32 8 232 212 195 128 93 215 255 255 HOP: 3 RSSI: -70.5 LQI: 127
|
||||
224 6 239 17 3 3 7 218 255 255 HOP: 4 RSSI: -69.5 LQI: 127
|
||||
80 7 237 255 115 7 72 162 255 255 HOP: 0 RSSI: -69 LQI: 127
|
||||
128 9 14 34 203 0 252 14 255 255 HOP: 1 RSSI: -68.5 LQI: 127
|
||||
```
|
||||
|
||||
If you are interested in the packet format, please:
|
||||
```
|
||||
Header byte0 byte1 byte2 byte3 byte4 byte5 byte6 byte7 byte8 Freq Sig_strength Link_quality
|
||||
224 13 3 17 3 3 32 253 255 255 HOP: 1 RSSI: -68.5 LQI: 127
|
||||
```
|
||||
|
||||
###9, explore data in Influx
|
||||
You're all set, let's look at the data
|
||||
```
|
||||
ssh 192.168.1.2
|
||||
influx
|
||||
> use weather
|
||||
Using database weather
|
||||
> select * from wind where time > now() - 1m group by type
|
||||
name: wind
|
||||
tags: type=direction
|
||||
time davis_id value
|
||||
---- -------- -----
|
||||
1590755264047546640 0 23.8
|
||||
1590755266495686261 0 12.6
|
||||
1590755269170611760 0 315
|
||||
1590755271670765583 0 4.2
|
||||
1590755274297615725 0 340.2
|
||||
1590755276695612090 0 351.4
|
||||
1590755279347820779 0 14
|
||||
1590755282048791933 0 14
|
||||
1590755284420807397 0 5.6
|
||||
1590755287147874950 0 5.6
|
||||
1590755289521471177 0 25.2
|
||||
1590755292271754999 0 323.4
|
||||
1590755294748104920 0 351.4
|
||||
1590755297195883784 0 350
|
||||
1590755302322174318 0 330.4
|
||||
1590755317723159515 0 333.2
|
||||
1590755320496027169 0 341.6
|
||||
|
||||
name: wind
|
||||
tags: type=speed
|
||||
time davis_id value
|
||||
---- -------- -----
|
||||
1590755264047546640 0 20.9
|
||||
1590755266495686261 0 20.9
|
||||
1590755269170611760 0 16.1
|
||||
1590755271670765583 0 25.7
|
||||
1590755274297615725 0 24.1
|
||||
1590755276695612090 0 22.5
|
||||
1590755279347820779 0 24.1
|
||||
1590755282048791933 0 22.5
|
||||
1590755284420807397 0 20.9
|
||||
1590755287147874950 0 17.7
|
||||
1590755289521471177 0 20.9
|
||||
1590755292271754999 0 22.5
|
||||
1590755294748104920 0 19.3
|
||||
1590755297195883784 0 22.5
|
||||
1590755302322174318 0 20.9
|
||||
1590755317723159515 0 11.3
|
||||
1590755320496027169 0 12.9
|
||||
|
||||
name: wind
|
||||
tags: type=windgust
|
||||
time davis_id value
|
||||
---- -------- -----
|
||||
1590755279347820779 0 25.7494
|
||||
```
|
||||
### Optionally, get grafana to plot the graphs for you
|
||||
Reference in New Issue
Block a user