├── 1w_d.py ├── CAN-USB-stick.py ├── CHANGELOG.md ├── LICENSE ├── N2K-from-SK.py ├── N2K-server_d.py ├── OP-signalk └── openplotter-settings.json ├── README.md ├── SK-base_d.py ├── add_tool10.py ├── check_rtimulib.py ├── classes ├── N2K_PGN.csv ├── N2K_send.py ├── __init__.py ├── actions.py ├── add_DS18B20.py ├── add_MCP.py ├── add_NMEA_0183.py ├── add_USBinst.py ├── add_action.py ├── add_deviation_setting.py ├── add_gpio.py ├── add_i2c.py ├── add_kplex.py ├── add_tool10.py ├── add_topic.py ├── add_trigger.py ├── add_value_setting.py ├── ads1115.py ├── bme280.py ├── check_vessel_self.py ├── conf.py ├── conf_analog.py ├── edit_i2c.py ├── getkeys.py ├── gmailbot.py ├── language.py ├── private_unit.json ├── select_key.py └── twitterbot.py ├── ctrl_actions.py ├── diagnostic-N2K-input.py ├── diagnostic-N2K-output.py ├── diagnostic-NMEA.py ├── diagnostic-SK-input.py ├── display800x480.py ├── docs ├── NMEA.html └── openplotter-documentation-en.pdf ├── emulator ├── GPIO.py ├── __init__.py └── w1thermsensor.py ├── keyword ├── locale ├── ca │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── de │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── en │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── es │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── eu │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── fr │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── gl │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po ├── it │ └── LC_MESSAGES │ │ ├── openplotter.mo │ │ └── openplotter.po └── nl │ └── LC_MESSAGES │ ├── openplotter.mo │ └── openplotter.po ├── message.py ├── mqtt_d.py ├── openplotter ├── openplotter.conf ├── openplotter.ico ├── openplotter_debug.ico ├── read_sensors_d.py ├── show_deviation_table.py ├── show_raw_adc_convert.py ├── sounds ├── Alien_Siren.mp3 ├── Annoying_Alarm_Clock.mp3 ├── BOMB_SIREN.mp3 ├── Beep.mp3 ├── Bleep.mp3 ├── Busy_Signal.mp3 ├── Buzz_Fade_In.mp3 ├── Buzz_Fade_Out.mp3 ├── Dog_Whistle.mp3 ├── Door_Buzzer.mp3 ├── Door_entry_notification.mp3 ├── Eas_Beep.mp3 ├── Fire_Alarm.mp3 ├── Fire_pager.mp3 ├── High_Pitch_Dog_Whistle.mp3 ├── House_Fire_Alarm.mp3 ├── Intruder_Alert.mp3 ├── Japanese_Temple_Bell_Small.mp3 ├── Loud_Alarm_Clock_Buzzer.mp3 ├── Metronome.mp3 ├── Plectron_tones.mp3 ├── Rooster.mp3 ├── Rooster_Crow.mp3 ├── Rooster_Crowing.mp3 ├── School_Fire_Alarm.mp3 ├── Ship_Bell.mp3 ├── Ship_Brass_Bell.mp3 ├── Siren.mp3 ├── Siren_Noise.mp3 ├── Smoke_Alarm.mp3 ├── Store_Door_Chime.mp3 ├── Temple_Bell.mp3 ├── Temple_Bell_Huge.mp3 ├── Tornado_Siren_II.mp3 ├── Warning_Siren.mp3 ├── Woop_Woop.mp3 ├── mandatory_evacuation.mp3 └── railroad_crossing_bell.mp3 ├── startup ├── test_sms.py ├── time_gps.py ├── tools ├── NMEA_0183_generator.py ├── NMEA_2000_generator.py ├── README.md ├── SDR_AIS.py ├── SDR_AIS_fine_cal.py ├── SDR_AIS_waterfall.py ├── SK-simulator.conf ├── SK-simulator.py ├── analog_ads1115.py ├── analog_ina219.py ├── autosetup_tty.py ├── calculate.py ├── demo_tool.py ├── example_tool_arduino2SK.py ├── example_tool_short_time2SK.py ├── install analog.txt ├── op_pymata_check.py ├── openplotter_analog.conf ├── oppymata.py └── rtl_433SK.py ├── unit-private.py ├── update ├── default_openplotter_desk.sh ├── update_OpenCPN.sh ├── update_OpenCPN_plugins.sh ├── update_OpenPlotter.sh ├── update_dependencies.sh └── update_settings.sh └── wifi_server.py /1w_d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import socket, time, platform 19 | if platform.machine()[0:3]!='arm': 20 | print 'this is not a raspberry pi -> no W1ThermSensor' 21 | else: 22 | from w1thermsensor import W1ThermSensor 23 | from classes.conf import Conf 24 | 25 | conf = Conf() 26 | 27 | try: 28 | sensors_list=eval(conf.get('1W', 'DS18B20')) 29 | except: sensors_list=[] 30 | 31 | if sensors_list: 32 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 33 | sensors=[] 34 | sensors_list2=[] 35 | for item in sensors_list: 36 | try: 37 | type=W1ThermSensor.THERM_SENSOR_DS18B20 38 | for sensor in W1ThermSensor.get_available_sensors(): 39 | if item[2] == sensor.id: 40 | type = sensor.type 41 | sensors.append(W1ThermSensor(type, item[2])) 42 | sensors_list2.append(item) 43 | except Exception,e: print str(e) 44 | 45 | while True: 46 | time.sleep(0.1) 47 | list_signalk=[] 48 | ib=0 49 | for i in sensors_list2: 50 | try: 51 | temp=sensors[ib].get_temperature(W1ThermSensor.KELVIN) 52 | temp_offset=temp+float(i[3]) 53 | value=str(temp_offset) 54 | path=i[1] 55 | name=i[0] 56 | SignalK='{"updates":[{"$source":"OPsensors.1W.'+name+'","values":[{"path":"'+path+'","value":'+value+'}]}]}\n' 57 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 58 | except Exception,e: print str(e) 59 | ib=ib+1 -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v0.17.1 2 | * Marking as stable 3 | * Ready for new upgrade v1.x.x 4 | 5 | v0.17.0 6 | * Fix calculate issues 7 | * Add suport for latest signal k versions 8 | * Remove node red freeboard 9 | * Relative openplotter-settings.json 10 | * Fix bug setting keys 11 | * Update languages 12 | * Enable and fix true wind in calculations 13 | * Check OP hat moitessier 14 | * Fix true heading calculation 15 | 16 | 17 | v0.16.0 18 | * Update languages 19 | * Add Basque and Galician languages 20 | * Fix issues with specials characters 21 | * Change update system 22 | * Fix issue with multilanguage actions and operators 23 | * Fix timestamp issue in actions 24 | * Include Avahi and Mdns 25 | * Update signal k keyswithmetadata.json file 26 | * Fix heel value issue 27 | 28 | v0.15.1 29 | * Update demo tool 30 | * Optimize classes for tools 31 | * Clean signal k tab interface 32 | * Add Italian language 33 | * Fix standalone tools startup 34 | * Update languages 35 | * Set development to beta 36 | 37 | v0.15.0 38 | * Fix compass performance 39 | * add ujson package 40 | * update tools README 41 | * Fix issue with actions and I2C 42 | * Fix issue with signal k keys in MQTT 43 | 44 | v0.14.5 45 | * Fix updates from 0.10.0 46 | * Fix start/stop all actions 47 | * Add OpenCPN default sentences to NMEA 0183 generator 48 | * Put config files into ~/.openplotter 49 | * Put custom tools into ~/.openplotter/tools 50 | * Create a demo custom tool 51 | * Remove upgrade raspbianfrom menu update 52 | * Fix some language issues 53 | * Optimize conf file management 54 | * Optimize paths and make them relative to an option in conf file 55 | * Force update if OP is upto date 56 | 57 | v0.14.4 58 | * Make updates standalone 59 | 60 | v0.14.3 61 | * Fix error afdding I2C sensors 62 | * Fix SignalK percent to ratio (0-100 -> 0-1) 63 | 64 | v0.14.2 65 | * Fix error when IMU is not defined 66 | 67 | v0.14.1 68 | * Remove deviation table from Compass tab 69 | 70 | v0.14.0 71 | * New IMU management, add Compass tab 72 | 73 | v0.13.1 74 | * Remove real VNC server and reinstall xrdp 75 | 76 | v0.13.0 77 | * Update dependencies 78 | * Update Raspbian packages 79 | * Switch source code to openplotter organization repository 80 | * Restore SK keys when editing 81 | * Add pop up when 1W is disabled 82 | * Add deg, knots, °C, F conversion on NMEA 0183 generator 83 | * Add default SK keys to I2C sensors 84 | * Add deviation table 85 | * Add deviation table to true heading calculation 86 | 87 | v0.12.0 88 | * Update dependencies 89 | * Update Raspbian packages 90 | * Switch to repository Nick-Currawong/RTIMULib2 91 | * Add IMU InvenSense MPU-9255 92 | * Fix IMU calibration buttons 93 | * Add Heading True calculation 94 | * Add Rate of Turn calculation 95 | 96 | v0.11.11 97 | * Remove unused packages when updating 98 | * Keep imu calibration data after updating 99 | 100 | v0.11.10 101 | * Add tool for INA21 102 | * Add USB tethering Android fixed IP 103 | * Update language sources 104 | * Fix hotspot 105 | * Add show calibration comparation tool 106 | * Fix magnetic variation calculation 107 | 108 | v0.11.9 109 | * Fix I2C sensors detection 110 | * Fix IMU ellipsoid calibration 111 | 112 | v0.11.8 113 | * I2C sensors detection workaround 114 | * Cosmetic changes 115 | * fix N2K output on startup issue 116 | 117 | v0.11.7 118 | * Add Set Signal K key value action 119 | * Improve error messages in actions 120 | * Add check I2C addresses button 121 | * Fix add MQTT interface error 122 | 123 | v0.11.6 124 | * Fix general MQTT topics actions 125 | * Fix SPI 126 | 127 | v0.11.5 128 | * Fix GPIO output actions 129 | * WIFI AP interface improvement 130 | 131 | v0.11.4 132 | * New interface for I2C 133 | * Fix I2C 134 | * Add support for BME280 sensors (press, temp, hum) 135 | 136 | v0.11.3 137 | * New interface for actions. Parsing signal k values on actions data. 138 | * Fix Twwitter and Gmail actions 139 | * Fix SMS actions 140 | * Fix sounds actions 141 | * Fix messages actions 142 | * Fix wait, reset, shutdown, startup stop, startup restart actions 143 | * Rename signal k settings labels 144 | * optimize signal k restart 145 | 146 | v0.11.2 147 | * Fix 1W 148 | * Fix NMEA 0183 generator 149 | * Fix ADS1115 150 | * Fix Actions. Some actions need still to be revised but triggers are working right. Stop and start all actions needs revision too 151 | 152 | v0.11.1 153 | * Add openplotter debugging to menu. To see the neu item go to: Updates - Set default openplotter desktop 154 | * Fix bug in CHANGELOG file 155 | 156 | v0.11.0 157 | * New interface for triggers (actions not working properly yet) 158 | * Fixing bug with NMEA 2000 sources 159 | * Optimizing Signal k diagnostic 160 | * Fixing bug with kplex 161 | * Optimizing startup 162 | * Adding up to 4 ADS1115 163 | * Update Signal k node server 164 | 165 | v0.10.2 166 | * updating new signal k settings file with old signal k settings 167 | 168 | v0.10.1 169 | * Liner providers deleted from UDP inputs in Signal K settings 170 | * Deleted unused serial input from Signal K settings 171 | * Deleted default N2K input from Signal K settings 172 | * Added this changelog file 173 | * Fixed sources in SK diagnostic window 174 | * Fixed sources in SK-base daemon 175 | 176 | -------------------------------------------------------------------------------- /N2K-server_d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import serial 19 | import socket 20 | import sys 21 | 22 | from classes.conf import Conf 23 | 24 | conf = Conf() 25 | 26 | activ = False 27 | activ = conf.get('N2K', 'output') == '1' 28 | if not activ: 29 | sys.exit(0) 30 | 31 | try: 32 | ser = serial.Serial(conf.get('N2K', 'can_usb'), 115200, timeout=0.5) 33 | except: 34 | print 'failed to start N2K output server on ' + conf.get('N2K', 'can_usb') 35 | sys.exit(0) 36 | 37 | 38 | Quelle = '127.0.0.1' # Adresse des eigenen Rechners 39 | Port = 55560 40 | 41 | e_udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # s.o. 42 | e_udp_sock.bind((Quelle, Port)) 43 | 44 | 45 | def SendCommandtoSerial(data): 46 | crc = 0 47 | # start = codecs.decode('1002', 'hex_codec') 48 | start = (0x10, 0x02) 49 | ende = (0x10, 0x03) 50 | i = 0 51 | while i < data[1] + 2: 52 | crc += data[i] 53 | i += 1 54 | crc = (256 - crc) & 255 55 | data[data[1] + 2] = crc 56 | i = 0 57 | ser.write(chr(start[0])) 58 | ser.write(chr(start[1])) 59 | while i < data[1] + 3: 60 | ser.write(chr(data[i])) 61 | # print format(data[i], '02x') 62 | if data[i] == 0x10: 63 | ser.write(chr(data[i])) 64 | i += 1 65 | ser.write(chr(ende[0])) 66 | ser.write(chr(ende[1])) 67 | 68 | def put_recive_to_serial(): 69 | while 1: 70 | data1, addr = e_udp_sock.recvfrom(512) 71 | # Data buffer had to be potenz of 2 72 | data = bytearray(data1) 73 | if data[7] + 9 == len(data): 74 | SendCommandtoSerial(data) 75 | datap = '' 76 | dat = 0 77 | for i in range(8, data[7] + 9): 78 | dat = dat + data[i] 79 | datap += ' ' + ('0' + hex(data[i])[2:])[-2:] 80 | 81 | put_recive_to_serial() 82 | -------------------------------------------------------------------------------- /OP-signalk/openplotter-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vessel": { 3 | "uuid": "urn:mrn:imo:mmsi:98765432" 4 | }, 5 | "pipedProviders": [ 6 | { 7 | "pipeElements": [ 8 | { 9 | "type": "providers/udp", 10 | "options": { 11 | "port": "55556" 12 | } 13 | }, 14 | { 15 | "type": "providers/nmea0183-signalk", 16 | "optionMappings": [ 17 | { 18 | "toOption": "selfId", 19 | "fromAppProperty": "selfId" 20 | }, 21 | { 22 | "toOption": "selfType", 23 | "fromAppProperty": "selfType" 24 | } 25 | ] 26 | } 27 | ], 28 | "id": "OPkplex" 29 | }, 30 | { 31 | "pipeElements": [ 32 | { 33 | "type": "providers/udp", 34 | "options": { 35 | "port": "55557" 36 | } 37 | }, 38 | { 39 | "type": "providers/from_json" 40 | } 41 | ], 42 | "id": "OPsensors" 43 | }, 44 | { 45 | "pipeElements": [ 46 | { 47 | "type": "providers/udp", 48 | "options": { 49 | "port": "55558" 50 | } 51 | }, 52 | { 53 | "type": "providers/from_json" 54 | } 55 | ], 56 | "id": "OPnotifications" 57 | }, 58 | { 59 | "pipeElements": [ 60 | { 61 | "type": "providers/udp", 62 | "options": { 63 | "port": "55559" 64 | } 65 | }, 66 | { 67 | "type": "providers/from_json" 68 | } 69 | ], 70 | "id": "OPserial" 71 | }, 72 | { 73 | "pipeElements": [ 74 | { 75 | "type": "providers/udp", 76 | "options": { 77 | "port": "55561" 78 | } 79 | }, 80 | { 81 | "type": "providers/from_json" 82 | } 83 | ], 84 | "id": "OPwifi" 85 | } 86 | ], 87 | "interfaces": { 88 | 89 | } 90 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Project site 2 | 3 | http://www.sailoog.com/openplotter 4 | 5 | This repository is obsolete. The active project is here: https://github.com/openplotter 6 | 7 | Development progress here: http://forum.openmarine.net/showthread.php?tid=1992 8 | -------------------------------------------------------------------------------- /add_tool10.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | 19 | class addTool10(wx.Dialog): 20 | 21 | def __init__(self): 22 | 23 | wx.Dialog.__init__(self, None, title=_('Standalone tool'), size=(130,230)) 24 | 25 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 26 | 27 | panel = wx.Panel(self) 28 | self.settings_b = wx.Button(panel,label=_('settings') , pos=(20, 20)) 29 | self.start_b = wx.Button(panel, label=_('start'), pos=(20, 60)) 30 | self.stop_b = wx.Button(panel, label=_('stop'), pos=(20, 100)) 31 | self.cancel_b = wx.Button(panel, label=_('cancel'), pos=(20, 140)) 32 | self.Bind(wx.EVT_BUTTON, self.on_Button) 33 | 34 | def on_Button(self,event): 35 | if self.settings_b.Id==event.Id: 36 | self.ButtonNr=1 37 | if self.start_b.Id==event.Id: 38 | self.ButtonNr=2 39 | if self.stop_b.Id==event.Id: 40 | self.ButtonNr=3 41 | if self.cancel_b.Id==event.Id: 42 | self.ButtonNr=4 43 | self.Close() -------------------------------------------------------------------------------- /check_rtimulib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import platform 19 | 20 | if platform.machine()[0:3]!='arm': print 'Error: This is not a Raspberry Pi -> no GPIO, I2C and SPI' 21 | else: import RTIMU 22 | 23 | try: 24 | 25 | SETTINGS_FILE = "RTIMULib" 26 | s = RTIMU.Settings(SETTINGS_FILE) 27 | imu = RTIMU.RTIMU(s) 28 | 29 | result = [['',''], ['',''], ['','']] 30 | 31 | with open(SETTINGS_FILE+'.ini', "r") as infile: 32 | for line in infile: 33 | if 'IMUType=' in line: 34 | tmp = line.split("=") 35 | IMUType = tmp[1].strip() 36 | if 'I2CSlaveAddress=' in line: 37 | tmp = line.split("=") 38 | I2CSlaveAddress = tmp[1].strip() 39 | if IMUType == '0': pass 40 | elif IMUType == '1': pass 41 | elif IMUType == '2': result[0][0] = 'InvenSense MPU-9150' 42 | elif IMUType == '3': result[0][0] = 'STM L3GD20H + LSM303D' 43 | elif IMUType == '4': result[0][0] = 'STM L3GD20 + LSM303DLHC' 44 | elif IMUType == '5': result[0][0] = 'STM LSM9DS0' 45 | elif IMUType == '6': result[0][0] = 'STM LSM9DS1' 46 | elif IMUType == '7': result[0][0] = 'InvenSense MPU-9250' 47 | elif IMUType == '8': result[0][0] = 'STM L3GD20H + LSM303DLHC' 48 | elif IMUType == '9': result[0][0] = 'Bosch BMX055' 49 | elif IMUType == '10': result[0][0] = 'Bosch BNX055' 50 | elif IMUType == '11': result[0][0] = 'InvenSense MPU-9255' 51 | if I2CSlaveAddress == '0': pass 52 | else: result[0][1] = hex(int(I2CSlaveAddress)) 53 | 54 | SETTINGS_FILE2 = "RTIMULib2" 55 | s2 = RTIMU.Settings(SETTINGS_FILE2) 56 | pressure = RTIMU.RTPressure(s2) 57 | humidity = RTIMU.RTHumidity(s2) 58 | 59 | with open(SETTINGS_FILE2+'.ini', "r") as infile: 60 | for line in infile: 61 | if 'PressureType=' in line: 62 | tmp = line.split("=") 63 | PressureType = tmp[1].strip() 64 | if 'I2CPressureAddress=' in line: 65 | tmp = line.split("=") 66 | I2CPressureAddress = tmp[1].strip() 67 | if 'HumidityType=' in line: 68 | tmp = line.split("=") 69 | HumidityType = tmp[1].strip() 70 | if 'I2CHumidityAddress=' in line: 71 | tmp = line.split("=") 72 | I2CHumidityAddress = tmp[1].strip() 73 | if PressureType == '0': pass 74 | elif PressureType == '1': pass 75 | elif PressureType == '2': result[1][0] = 'BMP180' 76 | elif PressureType == '3': result[1][0] = 'LPS25H' 77 | elif PressureType == '4': result[1][0] = 'MS5611' 78 | elif PressureType == '5': result[1][0] = 'MS5637' 79 | if I2CPressureAddress == '0': pass 80 | else: result[1][1] = hex(int(I2CPressureAddress)) 81 | if HumidityType == '0': pass 82 | elif HumidityType == '1': pass 83 | elif HumidityType == '2': result[2][0] = 'HTS221' 84 | elif HumidityType == '3': result[2][0] = 'HTU21D' 85 | if I2CHumidityAddress == '0': pass 86 | else: result[2][1] = hex(int(I2CHumidityAddress)) 87 | 88 | print 'result:'+str(result) 89 | 90 | except Exception, e: print "Error: "+str(e) 91 | -------------------------------------------------------------------------------- /classes/N2K_PGN.csv: -------------------------------------------------------------------------------- 1 | 59392,ISO Acknowledgement 2 | 59904,ISO Request 3 | 60928,ISO Address Claim 4 | 61184,ISO: Manu. Proprietary single-frame addressed 5 | 65001,Bus #1 Phase C Basic AC Quantities 6 | 65002,Bus #1 Phase B Basic AC Quantities 7 | 65003,Bus #1 Phase A Basic AC Quantities 8 | 65004,Bus #1 Average Basic AC Quantities 9 | 65005,Utility Total AC Energy 10 | 65006,Utility Phase C AC Reactive Power 11 | 65007,Utility Phase C AC Power 12 | 65008,Utility Phase C Basic AC Quantities 13 | 65009,Utility Phase B AC Reactive Power 14 | 65010,Utility Phase B AC Power 15 | 65011,Utility Phase B Basic AC Quantities 16 | 65012,Utility Phase A AC Reactive Power 17 | 65013,Utility Phase A AC Power 18 | 65014,Utility Phase A Basic AC Quantities 19 | 65015,Utility Total AC Reactive Power 20 | 65016,Utility Total AC Power 21 | 65017,Utility Average Basic AC Quantities 22 | 65018,Generator Total AC Energy 23 | 65019,Generator Phase C AC Reactive Power 24 | 65020,Generator Phase C AC Power 25 | 65021,Generator Phase C Basic AC Quantities 26 | 65022,Generator Phase B AC Reactive Power 27 | 65023,Generator Phase B AC Power 28 | 65024,Generator Phase B Basic AC Quantities 29 | 65025,Generator Phase A AC Reactive Power 30 | 65026,Generator Phase A AC Power 31 | 65027,Generator Phase A Basic AC Quantities 32 | 65028,Generator Total AC Reactive Power 33 | 65029,Generator Total AC Power 34 | 65030,Generator Average Basic AC Quantities 35 | 65240,ISO Commanded Address 36 | 65280,ISO: Manu. Proprietary single-frame non-addressed 37 | 65285,Boot State Acknowledgment 38 | 65286,Boot State Request 39 | 65287,Access Level 40 | 65289,Trim Tab Sensor Calibration 41 | 65290,Paddle Wheel Speed Configuration 42 | 65292,Clear Fluid Level Warnings 43 | 65293,LGC-2000 Configuration 44 | 65325,Reprogram Status 45 | 65341,Autopilot Mode 46 | 65408,Depth Quality Factor 47 | 65410,Device Information 48 | 65480,Autopilot Mode 49 | 126208,NMEA - Request/Command/Ack group function 50 | 126270,Slave Response 51 | 126464,PGN List (Transmit and Receive) 52 | 126720,NMEA 2000 options 53 | 126992,System Time 54 | 126996,Product Information 55 | 126998,Configuration Information 56 | 127237,Heading/Track control 57 | 127245,Rudder 58 | 127250,Vessel Heading 59 | 127251,Rate of Turn 60 | 127257,Attitude 61 | 127258,Magnetic Variation 62 | 127488,Engine Parameters, Rapid Update 63 | 127489,Engine Parameters, Dynamic 64 | 127493,Transmission Parameters, Dynamic 65 | 127496,Trip Parameters, Vessel 66 | 127497,Trip Parameters, Engine 67 | 127498,Engine Parameters, Static 68 | 127501,Binary Switch Bank Status 69 | 127502,Switch Bank Control 70 | 127503,AC Input Status 71 | 127504,AC Output Status 72 | 127505,Fluid Level 73 | 127506,DC Detailed Status 74 | 127507,Charger Status 75 | 127508,Battery Status 76 | 127509,Inverter Status 77 | 127510,Charger Configuration Status 78 | 127511,Inverter Configuration Status 79 | 127512,AGS Configuration Status 80 | 127513,Battery Configuration Status 81 | 127514,AGS Status 82 | 128259,Speed 83 | 128267,Water Depth 84 | 128275,Distance Log 85 | 128520,Tracked Target Data 86 | 129025,Position, Rapid Update 87 | 129026,COG & SOG, Rapid Update 88 | 129027,Position Delta, Rapid Update 89 | 129028,Altitude Delta, Rapid Update 90 | 129029,GNSS Position Data 91 | 129033,Time & Date 92 | 129038,AIS Class A Position Report 93 | 129039,AIS Class B Position Report 94 | 129040,AIS Class B Extended Position Report 95 | 129044,Datum 96 | 129045,User Datum 97 | 129283,Cross Track Error 98 | 129284,Navigation Data 99 | 129285,Navigation - Route/WP Information 100 | 129291,Set & Drift, Rapid Update 101 | 129301,Navigation - Route / Time to+from Mark 102 | 129302,Bearing and Distance between two Marks 103 | 129538,GNSS Control Status 104 | 129539,GNSS DOPs 105 | 129540,GNSS Sats in View 106 | 129541,GPS Almanac Data 107 | 129542,GNSS Pseudorange Noise Statistics 108 | 129545,GNSS RAIM Output 109 | 129546,GNSS RAIM Settings 110 | 129547,GNSS Pseudorange Error Statistics 111 | 129549,DGNSS Corrections 112 | 129550,GNSS Differential Correction Receiver Interface 113 | 129551,GNSS Differential Correction Receiver Signal 114 | 129556,GLONASS Almanac Data 115 | 129792,AIS DGNSS Broadcast Binary Message 116 | 129793,AIS UTC and Date Report 117 | 129794,AIS Class A Static and Voyage Related Data 118 | 129795,AIS Addressed Binary Message 119 | 129796,AIS Acknowledge 120 | 129797,AIS Binary Broadcast Message 121 | 129798,AIS SAR Aircraft Position Report 122 | 129799,Radio Frequency/Mode/Power 123 | 129800,AIS UTC/Date Inquiry 124 | 129801,AIS Addressed Safety Related Message 125 | 129802,AIS Safety Related Broadcast Message 126 | 129803,AIS Interrogation 127 | 129804,AIS Assignment Mode Command 128 | 129805,AIS Data Link Management Message 129 | 129806,AIS Channel Management 130 | 129807,AIS Class B Group Assignment 131 | 129808,DSC Call Information 132 | 129809,AIS Class B static data (msg 24 Part A) 133 | 129810,AIS Class B static data (msg 24 Part B) 134 | 130064,Route and WP Service - Database List 135 | 130065,Route and WP Service - Route List 136 | 130066,Route and WP Service - Route/WP-List Attributes 137 | 130067,Route and WP Service - Route - WP Name & Position 138 | 130068,Route and WP Service - Route - WP Name 139 | 130069,Route and WP Service - XTE Limit & Navigation Method 140 | 130070,Route and WP Service - WP Comment 141 | 130071,Route and WP Service - Route Comment 142 | 130072,Route and WP Service - Database Comment 143 | 130073,Route and WP Service - Radius of Turn 144 | 130074,Route and WP Service - WP List - WP Name & Position 145 | 130306,Wind Data 146 | 130310,Environmental Parameters 147 | 130311,Environmental Parameters 148 | 130312,Temperature 149 | 130313,Humidity 150 | 130314,Actual Pressure 151 | 130315,Set Pressure 152 | 130316,Temperature Extended Range 153 | 130320,Tide Station Data 154 | 130321,Salinity Station Data 155 | 130322,Current Station Data 156 | 130323,Meteorological Station Data 157 | 130324,Moored Buoy Station Data 158 | 130576,Small Craft Status 159 | 130577,Direction Data 160 | 130578,Vessel Speed Components 161 | 130816,SonicHub 162 | 130817,Navico: Product Information 163 | 130818,Simnet: Reprogram Data 164 | 130819,Simnet: Request Reprogram 165 | 130820,Fusion 166 | 130821,Furuno: Unknown 167 | 130827,Lowrance: unknown 168 | 130828,Simnet: Set Serial Number 169 | 130831,Suzuki: Engine and Storage Device Config 170 | 130832,Simnet: Fuel Used - High Resolution 171 | 130834,Simnet: Engine and Tank Configuration 172 | 130835,Simnet: Set Engine and Tank Configuration 173 | 130836,Simnet: Fluid Level Sensor Configuration 174 | 130837,Simnet: Fuel Flow Turbine Configuration 175 | 130838,Simnet: Fluid Level Warning 176 | 130839,Simnet: Pressure Sensor Configuration 177 | 130840,Simnet: Data User Group Configuration 178 | 130842,Simnet: AIS Class B static data 179 | 130843,Simnet: Sonar Status, Frequency and DSP Voltage 180 | 130845,Simnet: Parameter Handle 181 | 130850,Simnet: Event Command: AP command 182 | 130851,Simnet: Event Reply: AP command 183 | 130856,Simnet: Alarm Message 184 | 130880,Airmar: Additional Weather Data 185 | 130881,Airmar: Heater Control 186 | 130944,Airmar: POST 187 | 262161,Actisense: Operating mode 188 | 262384,Actisense: Startup status 189 | 262386,Actisense: System status 190 | 262388,Actisense: ? 191 | -------------------------------------------------------------------------------- /classes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/classes/__init__.py -------------------------------------------------------------------------------- /classes/add_DS18B20.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import platform 18 | import wx 19 | import re 20 | from select_key import selectKey 21 | 22 | if platform.machine()[0:3] == 'arm': 23 | from w1thermsensor import W1ThermSensor 24 | else: 25 | from emulator.w1thermsensor import W1ThermSensor 26 | 27 | 28 | class addDS18B20(wx.Dialog): 29 | def __init__(self, edit): 30 | 31 | if edit == 0: title = _('Add 1W temperature sensor') 32 | else: title = _('Edit 1W temperature sensor') 33 | 34 | wx.Dialog.__init__(self, None, title = title, size=(430, 250)) 35 | 36 | panel = wx.Panel(self) 37 | 38 | wx.StaticText(panel, label=_('Signal K key'), pos=(10, 10)) 39 | self.SKkey = wx.TextCtrl(panel, style=wx.CB_READONLY, size=(300, 30), pos=(10, 35)) 40 | 41 | self.edit_skkey = wx.Button(panel, label=_('Edit'), pos=(320, 32)) 42 | self.edit_skkey.Bind(wx.EVT_BUTTON, self.onEditSkkey) 43 | 44 | wx.StaticText(panel, label=_('Name'), pos=(10, 75)) 45 | self.name = wx.TextCtrl(panel, size=(150, 30), pos=(10, 100)) 46 | wx.StaticText(panel, label=_('allowed characters: 0-9, a-z, A-Z'), pos=(10, 135)) 47 | 48 | list_id = [] 49 | for sensor in W1ThermSensor.get_available_sensors(): 50 | list_id.append(sensor.id) 51 | wx.StaticText(panel, label=_('Sensor ID'), pos=(190, 75)) 52 | self.id_select = wx.ComboBox(panel, choices=list_id, style=wx.CB_READONLY, size=(150, 32), pos=(190, 100)) 53 | 54 | wx.StaticText(panel, label=_('Offset'), pos=(370, 75)) 55 | self.offset = wx.TextCtrl(panel, size=(50, 30), pos=(370, 100)) 56 | 57 | if edit != 0: 58 | self.name.SetValue(edit[1]) 59 | self.SKkey.SetValue(edit[2]) 60 | self.id_select.SetValue(edit[3]) 61 | self.offset.SetValue(edit[4]) 62 | 63 | cancelBtn = wx.Button(panel, wx.ID_CANCEL, pos=(115, 175)) 64 | okBtn = wx.Button(panel, wx.ID_OK, pos=(235, 175)) 65 | 66 | def onEditSkkey(self,e): 67 | key = self.SKkey.GetValue() 68 | dlg = selectKey(key) 69 | res = dlg.ShowModal() 70 | if res == wx.ID_OK: 71 | key = dlg.keys_list.GetValue() 72 | if '*' in key: 73 | wildcard = dlg.wildcard.GetValue() 74 | if wildcard: 75 | if not re.match('^[0-9a-zA-Z]+$', wildcard): 76 | self.ShowMessage(_('Failed. * must contain only allowed characters.')) 77 | dlg.Destroy() 78 | return 79 | key = key.replace('*',wildcard) 80 | else: 81 | self.ShowMessage(_('Failed. You have to provide a name for *.')) 82 | dlg.Destroy() 83 | return 84 | self.SKkey.SetValue(key) 85 | dlg.Destroy() 86 | 87 | 88 | def ShowMessage(self, w_msg): 89 | wx.MessageBox(w_msg, 'Info', wx.OK | wx.ICON_INFORMATION) -------------------------------------------------------------------------------- /classes/add_MCP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import json 18 | import subprocess 19 | import wx 20 | 21 | class addMCP(wx.Dialog): 22 | def __init__(self, edit, parent): 23 | self.conf = parent.conf 24 | self.edit = edit 25 | 26 | wx.Dialog.__init__(self, None, title=_('Edit MCP analog input ').decode('utf8') + str(edit[2]), size=(430, 350)) 27 | 28 | panel = wx.Panel(self) 29 | 30 | list_tmp = [] 31 | 32 | try: 33 | with open(self.home+'/.config/signalk-server-node/node_modules/@signalk/signalk-schema/dist/keyswithmetadata.json') as data_file: 34 | data = json.load(data_file) 35 | except: 36 | #old signalk 37 | with open(self.home+'/.config/signalk-server-node/node_modules/@signalk/signalk-schema/src/keyswithmetadata.json') as data_file: 38 | data = json.load(data_file) 39 | for i in self.data: 40 | ii = i.replace('/vessels/*/','') 41 | ii = ii.replace('RegExp','*') 42 | ii = ii.replace('/','.') 43 | list_tmp.append(ii) 44 | list_sk_path = sorted(list_tmp) 45 | 46 | titl = wx.StaticText(panel, label='Signal K') 47 | self.SKkey = wx.ComboBox(panel, choices=list_sk_path, style=wx.CB_READONLY) 48 | self.SKkey.Bind(wx.EVT_COMBOBOX, self.on_SKkey) 49 | self.description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY) 50 | self.description.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) 51 | 52 | self.asterix_t = wx.StaticText(panel, label=_('*')) 53 | self.asterix = wx.TextCtrl(panel, size=(150, -1)) 54 | self.asterix_t2 = wx.StaticText(panel, label=_('allowed characters: 0-9, a-z, A-Z')) 55 | 56 | self.aktiv = wx.CheckBox(panel, label=_('aktiv')) 57 | self.convert = wx.CheckBox(panel, label=_('convert')) 58 | self.convert.Bind(wx.EVT_CHECKBOX, self.on_convert) 59 | 60 | cancelBtn = wx.Button(panel, wx.ID_CANCEL) 61 | okBtn = wx.Button(panel, wx.ID_OK) 62 | 63 | hbox = wx.BoxSizer(wx.HORIZONTAL) 64 | hbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 65 | hbox.Add(cancelBtn, 0, wx.ALL | wx.EXPAND, 5) 66 | hbox.Add(okBtn, 0, wx.ALL | wx.EXPAND, 5) 67 | 68 | hboxb = wx.BoxSizer(wx.HORIZONTAL) 69 | hboxb.Add(self.asterix_t, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 70 | hboxb.Add(self.asterix, 0, wx.RIGHT | wx.LEFT, 5) 71 | hboxb.Add(self.asterix_t2, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 72 | 73 | vbox = wx.BoxSizer(wx.VERTICAL) 74 | vbox.Add(self.aktiv, 0, wx.ALL | wx.EXPAND, 5) 75 | vbox.AddSpacer(5) 76 | vbox.Add(titl, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 77 | vbox.Add(self.SKkey, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 78 | vbox.Add(self.description, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 79 | vbox.AddSpacer(5) 80 | vbox.Add(hboxb, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 81 | vbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 0) 82 | vbox.Add(self.convert, 0, wx.ALL | wx.EXPAND, 5) 83 | vbox.Add(hbox, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 84 | 85 | panel.SetSizer(vbox) 86 | self.panel = panel 87 | 88 | self.SKkey.SetValue(edit[3]) 89 | self.find_description(edit[3]) 90 | self.star_enable(edit[3]) 91 | self.asterix.SetValue(edit[4]) 92 | state = False 93 | if edit[1] == 1: state = True 94 | self.aktiv.SetValue(state) 95 | state = False 96 | if edit[5] == 1: state = True 97 | self.convert.SetValue(state) 98 | 99 | 100 | def find_description(self, SK): 101 | for i in self.data: 102 | ii = i.replace('/vessels/*/','') 103 | ii = ii.replace('RegExp','*') 104 | ii = ii.replace('/','.') 105 | if SK == ii: 106 | try: 107 | value_str = self.data[i]['description'] 108 | except: 109 | value_str = '' 110 | self.description.SetValue(value_str) 111 | if value_str == '': 112 | self.description.Hide() 113 | else: 114 | self.description.Show() 115 | self.panel.Layout() 116 | 117 | 118 | def star_enable(self, SK): 119 | if '*' in SK: 120 | self.asterix.Enable() 121 | self.asterix_t.Show() 122 | self.asterix.Show() 123 | self.asterix_t2.Show() 124 | else: 125 | self.asterix.Disable() 126 | self.asterix_t.Hide() 127 | self.asterix.Hide() 128 | self.asterix_t2.Hide() 129 | self.panel.Layout() 130 | 131 | 132 | def on_SKkey(self, e): 133 | selected = self.SKkey.GetValue() 134 | self.find_description(selected) 135 | self.star_enable(selected) 136 | 137 | 138 | def on_convert(self, e): 139 | convert = 0 140 | if self.convert.GetValue(): 141 | convert = 1 142 | if self.conf.has_option('SPI', 'value_' + str(self.edit[2])): 143 | data = self.conf.get('SPI', 'value_' + str(self.edit[2])) 144 | try: 145 | temp_list = eval(data) 146 | except: 147 | temp_list = [] 148 | min = 1023 149 | max = 0 150 | for ii in temp_list: 151 | if ii[0] > max: max = ii[0] 152 | if ii[0] < min: min = ii[0] 153 | if min > 0: 154 | wx.MessageBox(_('minimum raw value in setting table > 0'), 'info', wx.OK | wx.ICON_INFORMATION) 155 | convert = 0 156 | if max < 1023: 157 | wx.MessageBox(_('maximum raw value in setting table < 1023'), 'info', wx.OK | wx.ICON_INFORMATION) 158 | convert = 0 159 | else: 160 | wx.MessageBox(_('no option value ').decode('utf8') + str(self.edit[2]) + _(' in openplotter.conf').decode('utf8'), 'info', 161 | wx.OK | wx.ICON_INFORMATION) 162 | convert = 0 163 | 164 | self.convert.SetValue(convert) 165 | -------------------------------------------------------------------------------- /classes/add_USBinst.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | 19 | 20 | class addUSBinst(wx.Dialog): 21 | def __init__(self, edit, parent): 22 | 23 | self.parent = parent 24 | 25 | wx.Dialog.__init__(self, None, title=_('Add individual name to serial port'), size=(580, 300)) 26 | 27 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 28 | 29 | panel = wx.Panel(self) 30 | 31 | self.list_devices = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER, size=(565, 120)) 32 | self.list_devices.SetPosition((5, 5)) 33 | self.list_devices.InsertColumn(0, _('random name'), width=113) 34 | self.list_devices.InsertColumn(1, _('vendor'), width=60) 35 | self.list_devices.InsertColumn(2, _('product'), width=65) 36 | self.list_devices.InsertColumn(3, _('port'), width=90) 37 | self.list_devices.InsertColumn(4, _('serial'), width=65) 38 | self.list_devices.InsertColumn(5, _('info'), width=600) 39 | self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.select_device, self.list_devices) 40 | 41 | wx.StaticText(panel, label=_('new name'), pos=(15, 140)) 42 | self.OPname_label = wx.StaticText(panel, label='/dev/ttyOP_', pos=(15, 170)) 43 | self.OPname_select = wx.TextCtrl(panel, size=(100, 30), pos=(90, 160)) 44 | self.OPname_select.Disable() 45 | self.OPname_label.Disable() 46 | 47 | self.rem_dev = wx.CheckBox(panel, label=_('Remember device (by vendor, product,(serial))'), pos=(245, 140)) 48 | self.rem_dev.Bind(wx.EVT_CHECKBOX, self.on_enable_dev) 49 | self.rem_dev.Disable() 50 | self.rem_dev.SetValue(True) 51 | self.rem = 'dev' 52 | 53 | self.rem_port = wx.CheckBox(panel, label=_('Remember port (positon on the USB-hub)'), pos=(245, 165)) 54 | self.rem_port.Bind(wx.EVT_CHECKBOX, self.on_enable_port) 55 | self.rem_port.Disable() 56 | 57 | if edit != 0: 58 | self.OPname_select.SetValue(edit[1][6:]) 59 | self.rem_dev.SetValue(edit[6] == 'dev') 60 | self.rem_port.SetValue(edit[6] == 'port') 61 | self.rem = edit[6] 62 | 63 | self.vendor = edit[2] 64 | self.product = edit[3] 65 | self.serial = edit[4] 66 | self.con_port = edit[5] 67 | self.device = edit[7] 68 | 69 | self.OPname_select.Enable() 70 | self.rem_dev.Enable() 71 | self.rem_port.Enable() 72 | wx.StaticText(panel, 73 | label=self.vendor + ' ' + self.product + ' ' + self.con_port + ' ' + self.serial, 74 | pos=(15, 200)) 75 | 76 | else: 77 | # context = pyudev.Context() 78 | context = self.parent.context 79 | 80 | for device in context.list_devices(subsystem='tty'): 81 | i = device['DEVNAME'] 82 | if '/dev/ttyACM' in i or '/dev/ttyUSB' in i: 83 | ii = device['DEVLINKS'] 84 | if '/dev/ttyOP' in ii: 85 | pass 86 | else: 87 | value = device['DEVPATH'] 88 | value_DEVPATH = value[value.rfind('/usb1/') + 6:-(len(value) - value.find('/tty'))] 89 | value_DEVPATH = value_DEVPATH[value_DEVPATH.rfind('/') + 1:] 90 | try: 91 | serial = device['ID_SERIAL_SHORT'] 92 | except: 93 | serial = '' 94 | try: 95 | vendor_db = device['ID_VENDOR_FROM_DATABASE'] 96 | except: 97 | vendor_db = '' 98 | try: 99 | model_db = device['ID_MODEL_FROM_DATABASE'] 100 | except: 101 | model_db = '' 102 | self.list_devices.Append( 103 | [i, device['ID_VENDOR_ID'], device['ID_MODEL_ID'], value_DEVPATH, serial, 104 | vendor_db + ' ' + model_db]) 105 | 106 | cancelBtn = wx.Button(panel, wx.ID_CANCEL, pos=(195, 220)) 107 | okBtn = wx.Button(panel, wx.ID_OK, pos=(305, 220)) 108 | 109 | def on_enable_dev(self, e): 110 | if self.rem_dev.GetValue(): 111 | self.rem_port.SetValue(False) 112 | self.rem = 'dev' 113 | else: 114 | self.rem_port.SetValue(True) 115 | self.rem = 'port' 116 | 117 | def on_enable_port(self, e): 118 | if self.rem_port.GetValue(): 119 | self.rem_dev.SetValue(False) 120 | self.rem = 'port' 121 | else: 122 | self.rem_dev.SetValue(True) 123 | self.rem = 'dev' 124 | 125 | def select_device(self, e): 126 | selected_device = e.GetIndex() 127 | item = self.list_devices.GetItem(selected_device, 0) 128 | self.device = item.GetText()[5:-1] 129 | item = self.list_devices.GetItem(selected_device, 1) 130 | self.vendor = item.GetText() 131 | item = self.list_devices.GetItem(selected_device, 2) 132 | self.product = item.GetText() 133 | item = self.list_devices.GetItem(selected_device, 3) 134 | self.con_port = item.GetText() 135 | item = self.list_devices.GetItem(selected_device, 4) 136 | self.serial = item.GetText() 137 | self.OPname_select.Enable() 138 | self.OPname_label.Enable() 139 | self.rem_dev.Enable() 140 | self.rem_port.Enable() 141 | -------------------------------------------------------------------------------- /classes/add_action.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx, os, re 18 | from select_key import selectKey 19 | 20 | class addAction(wx.Dialog): 21 | def __init__(self, parent, actions_options, time_units, edit): 22 | 23 | if edit == 0: title = _('Add action') 24 | else: title = _('Edit action') 25 | 26 | wx.Dialog.__init__(self, None, title=title, size=(450, 400)) 27 | 28 | panel = wx.Panel(self) 29 | self.conf = parent.conf 30 | self.actions_options = actions_options 31 | 32 | self.home = parent.home 33 | self.currentpath = parent.currentpath 34 | 35 | list_actions = [] 36 | for i in self.actions_options: 37 | list_actions.append(i[0]) 38 | 39 | label_action = wx.StaticText(panel, label=_('action')) 40 | self.action_select = wx.ComboBox(panel, choices=list_actions, style=wx.CB_READONLY) 41 | self.action_select.Bind(wx.EVT_COMBOBOX, self.onSelect) 42 | 43 | hline1 = wx.StaticLine(panel) 44 | 45 | label_data = wx.StaticText(panel, label=_('data')) 46 | self.data = wx.TextCtrl(panel, style=wx.TE_MULTILINE) 47 | 48 | self.edit_skkey = wx.Button(panel, label=_('Add Signal K key')) 49 | self.edit_skkey.Bind(wx.EVT_BUTTON, self.onEditSkkey) 50 | 51 | hline2 = wx.StaticLine(panel) 52 | 53 | label_repeat = wx.StaticText(panel, label=_('repeat after')) 54 | self.repeat = wx.TextCtrl(panel) 55 | self.repeat.Disable() 56 | 57 | self.repeat_unit = wx.ComboBox(panel, choices=time_units, style=wx.CB_READONLY) 58 | self.repeat_unit.Bind(wx.EVT_COMBOBOX, self.onSelectUnit) 59 | self.repeat_unit.SetValue(_('no repeat')) 60 | 61 | cancelBtn = wx.Button(panel, wx.ID_CANCEL) 62 | okBtn = wx.Button(panel, wx.ID_OK) 63 | 64 | hbox = wx.BoxSizer(wx.HORIZONTAL) 65 | hbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 66 | hbox.Add(cancelBtn, 0, wx.ALL | wx.EXPAND, 5) 67 | hbox.Add(okBtn, 0, wx.ALL | wx.EXPAND, 5) 68 | 69 | hbox2 = wx.BoxSizer(wx.HORIZONTAL) 70 | hbox2.Add(self.repeat, 1, wx.LEFT | wx.EXPAND, 5) 71 | hbox2.Add(self.repeat_unit, 1, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 72 | 73 | hbox3 = wx.BoxSizer(wx.HORIZONTAL) 74 | hbox3.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 75 | hbox3.Add(self.edit_skkey, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 76 | 77 | vbox = wx.BoxSizer(wx.VERTICAL) 78 | vbox.AddSpacer(5) 79 | vbox.Add(label_action, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 80 | vbox.Add(self.action_select, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 81 | vbox.Add(hline1, 0, wx.ALL | wx.EXPAND, 5) 82 | vbox.Add(label_data, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 83 | vbox.Add(self.data, 4, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 84 | vbox.AddSpacer(5) 85 | vbox.Add(hbox3, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 86 | vbox.Add(hline2, 0, wx.ALL | wx.EXPAND, 5) 87 | vbox.Add(label_repeat, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 88 | vbox.Add(hbox2, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 0) 89 | vbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 0) 90 | vbox.Add(hbox, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 91 | 92 | panel.SetSizer(vbox) 93 | self.panel = panel 94 | 95 | if edit != 0: 96 | self.action_select.SetValue(list_actions[edit[1]]) 97 | self.data.SetValue(edit[2]) 98 | if edit[3] != 0.0: 99 | self.repeat.SetValue(str(edit[3])) 100 | self.repeat.Enable() 101 | self.repeat_unit.SetValue(time_units[edit[4]]) 102 | 103 | def onSelect(self, e): 104 | option = self.actions_options[self.action_select.GetCurrentSelection()][0] 105 | msg = self.actions_options[self.action_select.GetCurrentSelection()][1] 106 | field = self.actions_options[self.action_select.GetCurrentSelection()][2] 107 | if field == 0: 108 | self.data.Disable() 109 | self.data.SetValue('') 110 | self.edit_skkey.Disable() 111 | if field == 1: 112 | self.data.Enable() 113 | self.data.SetFocus() 114 | self.edit_skkey.Enable() 115 | if msg: 116 | if msg == 'OpenFileDialog': 117 | dlg = wx.FileDialog(self, message=_('Choose a file'), defaultDir=self.currentpath + '/sounds', 118 | defaultFile='', 119 | wildcard=_('Audio files').decode('utf8') + ' (*.mp3)|*.mp3|' + _('All files').decode('utf8') + ' (*.*)|*.*', 120 | style=wx.OPEN | wx.CHANGE_DIR) 121 | if dlg.ShowModal() == wx.ID_OK: 122 | file_path = dlg.GetPath() 123 | self.data.SetValue(file_path) 124 | print self.currentpath 125 | os.chdir(self.currentpath) 126 | dlg.Destroy() 127 | else: 128 | if msg == 0: 129 | pass 130 | else: 131 | if field == 1 and option != _('wait'): 132 | msg = msg+ _('\n\nYou can add the current value of any Signal K key typing its name between angle brackets, e.g: ') 133 | wx.MessageBox(msg, 'Info', wx.OK | wx.ICON_INFORMATION) 134 | 135 | def onSelectUnit(self, e): 136 | if self.repeat_unit.GetCurrentSelection() == 0: 137 | self.repeat.Disable() 138 | self.repeat.SetValue('') 139 | else: 140 | self.repeat.Enable() 141 | 142 | def onEditSkkey(self,e): 143 | 144 | dlg = selectKey('') 145 | res = dlg.ShowModal() 146 | if res == wx.ID_OK: 147 | key = dlg.keys_list.GetValue() 148 | if '*' in key: 149 | wildcard = dlg.wildcard.GetValue() 150 | if wildcard: 151 | if not re.match('^[0-9a-zA-Z]+$', wildcard): 152 | self.ShowMessage(_('Failed. * must contain only allowed characters.')) 153 | dlg.Destroy() 154 | return 155 | key = key.replace('*',wildcard) 156 | else: 157 | self.ShowMessage(_('Failed. You have to provide a name for *.')) 158 | dlg.Destroy() 159 | return 160 | self.data.SetValue(self.data.GetValue()+'<'+key+'>') 161 | dlg.Destroy() 162 | 163 | def ShowMessage(self, w_msg): 164 | wx.MessageBox(w_msg, 'Info', wx.OK | wx.ICON_INFORMATION) 165 | -------------------------------------------------------------------------------- /classes/add_gpio.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | 19 | 20 | class addGPIO(wx.Dialog): 21 | def __init__(self, avalaible_gpio, edit): 22 | 23 | wx.Dialog.__init__(self, None, title=_('Add GPIO sensor'), size=(330, 265)) 24 | 25 | panel = wx.Panel(self) 26 | 27 | wx.StaticText(panel, label=_('Name'), pos=(10, 10)) 28 | self.name = wx.TextCtrl(panel, size=(310, 30), pos=(10, 35)) 29 | 30 | wx.StaticText(panel, label=_('allowed characters: 0-9, a-z, A-Z'), pos=(10, 70)) 31 | 32 | list_io = [_('input'), _('output')] 33 | wx.StaticText(panel, label=_('I/O'), pos=(10, 100)) 34 | self.io_select = wx.ComboBox(panel, choices=list_io, style=wx.CB_READONLY, size=(100, 32), pos=(10, 125)) 35 | self.io_select.Bind(wx.EVT_COMBOBOX, self.onSelectIO) 36 | 37 | wx.StaticText(panel, label=_('GPIO'), pos=(115, 100)) 38 | self.gpio_select = wx.ComboBox(panel, choices=avalaible_gpio, style=wx.CB_READONLY, size=(100, 32), 39 | pos=(115, 125)) 40 | 41 | list_pull = ['down', 'up'] 42 | wx.StaticText(panel, label=_('Pull'), pos=(220, 100)) 43 | self.pull_select = wx.ComboBox(panel, choices=list_pull, style=wx.CB_READONLY, size=(100, 32), pos=(220, 125)) 44 | 45 | if edit != 0: 46 | self.name.SetValue(edit[1]) 47 | if edit[2] == 'out': 48 | io = _('output') 49 | self.pull_select.Disable() 50 | else: 51 | io = _('input') 52 | self.pull_select.Enable() 53 | self.io_select.SetValue(io) 54 | self.gpio_select.SetValue(str(edit[3])) 55 | self.pull_select.SetValue(edit[4]) 56 | 57 | cancelBtn = wx.Button(panel, wx.ID_CANCEL, pos=(70, 180)) 58 | okBtn = wx.Button(panel, wx.ID_OK, pos=(180, 180)) 59 | 60 | def onSelectIO(self, e): 61 | selected = self.io_select.GetValue() 62 | if selected == _('input'): self.pull_select.Enable() 63 | if selected == _('output'): self.pull_select.Disable() 64 | -------------------------------------------------------------------------------- /classes/add_i2c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import platform 18 | import wx, subprocess, os 19 | 20 | if platform.machine()[0:3] == 'arm': 21 | import smbus 22 | 23 | 24 | class addI2c(wx.Dialog): 25 | def __init__(self, parent): 26 | 27 | title = _('Add I2C sensor') 28 | 29 | wx.Dialog.__init__(self, None, title=title, size=(450, 400)) 30 | 31 | panel = wx.Panel(self) 32 | self.conf = parent.conf 33 | self.home = parent.home 34 | self.currentpath = parent.currentpath 35 | self.parent = parent 36 | label_detected = wx.StaticText(panel, label=_('detected')) 37 | 38 | self.list_detected = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER) 39 | self.list_detected.InsertColumn(0, _('Name'), width=210) 40 | self.list_detected.InsertColumn(1, _('Address'), width=116) 41 | self.list_detected.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSelectDetected) 42 | 43 | self.reset = wx.Button(panel, label=_('Reset')) 44 | self.reset.Bind(wx.EVT_BUTTON, self.onReset) 45 | 46 | self.check_addresses = wx.Button(panel, label=_('Addresses')) 47 | self.check_addresses.Bind(wx.EVT_BUTTON, self.onCheckAddresses) 48 | 49 | hline1 = wx.StaticLine(panel) 50 | 51 | label_add = wx.StaticText(panel, label=_('add/update sensor')) 52 | 53 | self.list_sensors = [] 54 | for i in parent.i2c_sensors_def: 55 | self.list_sensors.append(i[0]) 56 | self.sensor_select = wx.ComboBox(panel, choices=self.list_sensors, style=wx.CB_READONLY) 57 | self.sensor_select.Bind(wx.EVT_COMBOBOX, self.onSelectSensor) 58 | 59 | self.address = wx.TextCtrl(panel) 60 | 61 | cancelBtn = wx.Button(panel, wx.ID_CANCEL) 62 | okBtn = wx.Button(panel, wx.ID_OK) 63 | 64 | vbox1 = wx.BoxSizer(wx.VERTICAL) 65 | vbox1.Add(self.reset, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 66 | vbox1.Add(self.check_addresses, 0, wx.RIGHT | wx.LEFT | wx.UP | wx.EXPAND, 5) 67 | vbox1.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 68 | 69 | hbox2 = wx.BoxSizer(wx.HORIZONTAL) 70 | hbox2.Add(self.list_detected, 1, wx.LEFT | wx.EXPAND, 5) 71 | hbox2.Add(vbox1, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 72 | 73 | hbox3 = wx.BoxSizer(wx.HORIZONTAL) 74 | hbox3.Add(self.sensor_select, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 75 | hbox3.Add(self.address, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 76 | 77 | hbox = wx.BoxSizer(wx.HORIZONTAL) 78 | hbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 79 | hbox.Add(cancelBtn, 0, wx.ALL | wx.EXPAND, 5) 80 | hbox.Add(okBtn, 0, wx.ALL | wx.EXPAND, 5) 81 | 82 | vbox = wx.BoxSizer(wx.VERTICAL) 83 | vbox.AddSpacer(5) 84 | vbox.Add(label_detected, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 85 | vbox.Add(hbox2, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 86 | vbox.Add(hline1, 0, wx.ALL | wx.EXPAND, 5) 87 | vbox.Add(label_add, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 88 | vbox.Add(hbox3, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 89 | vbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 0) 90 | vbox.Add(hbox, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 91 | 92 | panel.SetSizer(vbox) 93 | self.panel = panel 94 | 95 | self.detection() 96 | 97 | def onSelectDetected(self, e): 98 | selectedDetected = self.list_detected.GetFirstSelected() 99 | name = self.list_detected.GetItem(selectedDetected, 0) 100 | address = self.list_detected.GetItem(selectedDetected, 1) 101 | self.sensor_select.SetValue(name.GetText()) 102 | if name.GetText() in self.list_sensors: self.address.SetValue(address.GetText()) 103 | 104 | def onSelectSensor(self, e): 105 | self.address.SetValue('') 106 | 107 | def onReset(self, e): 108 | dlg = wx.MessageDialog(None, _('If your sensors are not detected right, try resetting system or forcing name and address.\n\nDo you want to try auto detection again?'),_('Question'), wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) 109 | if dlg.ShowModal() == wx.ID_YES: 110 | try: 111 | os.remove(self.home + '/.pypilot/RTIMULib2.ini') 112 | except: pass 113 | self.detection() 114 | dlg.Destroy() 115 | 116 | def onCheckAddresses(self, e): 117 | addresses = '' 118 | try: 119 | addresses = subprocess.check_output(['i2cdetect', '-y', '1']) 120 | except: 121 | addresses = subprocess.check_output(['i2cdetect', '-y', '2']) 122 | wx.MessageBox(addresses, _('Detected I2C addresses'), wx.OK | wx.ICON_INFORMATION) 123 | 124 | def detection(self): 125 | if platform.machine()[0:3] == 'arm': 126 | self.list_detected.DeleteAllItems() 127 | #RTIMULIB sensors 128 | rtimulib = self.parent.check_i2c() 129 | self.printRtimulibResults(rtimulib) 130 | #others 131 | bus = smbus.SMBus(1) 132 | for addr in range(3, 178): 133 | try: 134 | bus.write_quick(addr) 135 | addr = hex(addr) 136 | if addr == '0x76': self.list_detected.Append(['BME280', addr]) 137 | except IOError: pass 138 | 139 | def printRtimulibResults(self,rtimulib): 140 | try: 141 | temp_list = eval(rtimulib) 142 | except: 143 | temp_list = [] 144 | if temp_list: 145 | if temp_list[0][0] and temp_list[0][1]: self.list_detected.Append([temp_list[0][0], temp_list[0][1]]) 146 | if temp_list[1][0] and temp_list[1][1]: self.list_detected.Append([temp_list[1][0], temp_list[1][1]]) 147 | if temp_list[2][0] and temp_list[2][1]: self.list_detected.Append([temp_list[2][0], temp_list[2][1]]) 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /classes/add_tool10.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | 19 | 20 | class addTool10(wx.Dialog): 21 | def __init__(self): 22 | self.ButtonNr = 1 23 | wx.Dialog.__init__(self, None, title=_('Add individual name to serial port'), size=(130, 230)) 24 | 25 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 26 | 27 | panel = wx.Panel(self) 28 | self.settings_b = wx.Button(panel, label=_('settings'), pos=(20, 20)) 29 | self.start_b = wx.Button(panel, label=_('start'), pos=(20, 60)) 30 | self.stop_b = wx.Button(panel, label=_('stop'), pos=(20, 100)) 31 | self.cancel_b = wx.Button(panel, label=_('cancel'), pos=(20, 140)) 32 | self.Bind(wx.EVT_BUTTON, self.on_Button) 33 | 34 | def on_Button(self, event): 35 | if self.settings_b.Id == event.Id: 36 | self.ButtonNr = 1 37 | if self.start_b.Id == event.Id: 38 | self.ButtonNr = 2 39 | if self.stop_b.Id == event.Id: 40 | self.ButtonNr = 3 41 | if self.cancel_b.Id == event.Id: 42 | self.ButtonNr = 4 43 | event.Skip() 44 | self.Close() 45 | -------------------------------------------------------------------------------- /classes/add_topic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx, re 18 | from select_key import selectKey 19 | 20 | class addTopic(wx.Dialog): 21 | def __init__(self, edit): 22 | 23 | if edit == 0: title = _('Add MQTT topic') 24 | else: title = _('Edit MQTT topic') 25 | 26 | wx.Dialog.__init__(self, None, title = title, size=(430, 280)) 27 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 28 | 29 | panel = wx.Panel(self) 30 | 31 | self.topiclabel = wx.StaticText(panel, label=_('Topic'), pos=(10, 10)) 32 | wx.StaticText(panel, label=_('allowed characters: 0-9, a-z, A-Z'), pos=(150, 10)) 33 | self.topic = wx.TextCtrl(panel, size=(410, 30), pos=(10, 30)) 34 | 35 | list_type = [_('General'), _('Signal K key input'), _('Signal K delta input')] 36 | wx.StaticText(panel, label=_('Type'), pos=(10, 70)) 37 | self.type = wx.ComboBox(panel, choices=list_type, style=wx.CB_READONLY, size=(200, 32), pos=(10, 90)) 38 | self.type.Bind(wx.EVT_COMBOBOX, self.onSelect_type) 39 | 40 | self.skkeylabel = wx.StaticText(panel, label=_('Signal K key'), pos=(10, 130)) 41 | self.skkey = wx.TextCtrl(panel, style=wx.CB_READONLY, size=(300, 30), pos=(10, 150)) 42 | 43 | self.edit_skkey = wx.Button(panel, label=_('Edit'), pos=(320, 147)) 44 | self.edit_skkey.Bind(wx.EVT_BUTTON, self.onEditSkkey) 45 | 46 | self.skkeylabel.Disable() 47 | self.skkey.Disable() 48 | self.edit_skkey.Disable() 49 | 50 | if edit != 0: 51 | self.topic.SetValue(edit[1][0]) 52 | if edit[1][1] == 0: 53 | self.type.SetValue(_('General')) 54 | elif edit[1][1] == 1: 55 | self.type.SetValue(_('Signal K key input')) 56 | self.skkey.SetValue(edit[1][2]) 57 | self.skkeylabel.Enable() 58 | self.skkey.Enable() 59 | self.edit_skkey.Enable() 60 | elif edit[1][1] == 2: 61 | self.type.SetValue(_('Signal K delta input')) 62 | 63 | cancelBtn = wx.Button(panel, wx.ID_CANCEL, pos=(120, 210)) 64 | okBtn = wx.Button(panel, wx.ID_OK, pos=(230, 210)) 65 | 66 | def onEditSkkey(self,e): 67 | key = self.skkey.GetValue() 68 | dlg = selectKey(key) 69 | res = dlg.ShowModal() 70 | if res == wx.ID_OK: 71 | key = dlg.keys_list.GetValue() 72 | if '*' in key: 73 | wildcard = dlg.wildcard.GetValue() 74 | if wildcard: 75 | if not re.match('^[0-9a-zA-Z]+$', wildcard): 76 | self.ShowMessage(_('Failed. * must contain only allowed characters.')) 77 | dlg.Destroy() 78 | return 79 | key = key.replace('*',wildcard) 80 | else: 81 | self.ShowMessage(_('Failed. You have to provide a name for *.')) 82 | dlg.Destroy() 83 | return 84 | dlg.Destroy() 85 | self.skkey.SetValue(key) 86 | 87 | def onSelect_type(self,e): 88 | if self.type.GetValue() == _('Signal K key input'): 89 | self.skkeylabel.Enable() 90 | self.skkey.Enable() 91 | self.edit_skkey.Enable() 92 | else: 93 | self.skkeylabel.Disable() 94 | self.skkey.Disable() 95 | self.edit_skkey.Disable() 96 | 97 | def ShowMessage(self, w_msg): 98 | wx.MessageBox(w_msg, 'Info', wx.OK | wx.ICON_INFORMATION) -------------------------------------------------------------------------------- /classes/add_value_setting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | import subprocess 19 | 20 | 21 | class addvaluesetting(wx.Dialog): 22 | def __init__(self, edit, parent): 23 | self.parent = parent 24 | self.conf = parent.conf 25 | self.edit = edit 26 | self.listsave = [] 27 | 28 | wx.Dialog.__init__(self, None, title=_('convert analog value to expected value of input ').decode('utf8') + str(edit), 29 | size=(460, 350)) 30 | 31 | panel = wx.Panel(self) 32 | 33 | self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER) 34 | self.list.InsertColumn(0, _('adc value'), width=80) 35 | self.list.InsertColumn(1, _('value in unit'), width=100) 36 | 37 | rawvalue_t = wx.StaticText(panel, label=_('raw adc value')) 38 | self.rawvalue = wx.TextCtrl(panel, size=(150, 30)) 39 | 40 | unitvalue_t = wx.StaticText(panel, label=_('value in required unit')) 41 | self.unitvalue = wx.TextCtrl(panel, size=(150, 30)) 42 | 43 | add = wx.Button(panel, label=_('add')) 44 | add.Bind(wx.EVT_BUTTON, self.on_add) 45 | 46 | delete = wx.Button(panel, label=_('delete')) 47 | delete.Bind(wx.EVT_BUTTON, self.on_delete) 48 | 49 | close = wx.Button(panel, label=_('Close')) 50 | close.Bind(wx.EVT_BUTTON, self.on_close) 51 | 52 | graph = wx.Button(panel, label=_('graph')) 53 | graph.Bind(wx.EVT_BUTTON, self.on_graph) 54 | 55 | vb1 = wx.BoxSizer(wx.VERTICAL) 56 | vb1.Add(rawvalue_t, 0, wx.ALL | wx.EXPAND, 5) 57 | vb1.Add(self.rawvalue, 0, wx.ALL | wx.EXPAND, 5) 58 | vb1.AddSpacer(10) 59 | vb1.Add(unitvalue_t, 0, wx.ALL | wx.EXPAND, 5) 60 | vb1.Add(self.unitvalue, 0, wx.ALL | wx.EXPAND, 5) 61 | 62 | hlistbox = wx.BoxSizer(wx.HORIZONTAL) 63 | hlistbox.Add(self.list, 1, wx.ALL | wx.EXPAND, 5) 64 | hlistbox.Add(vb1, 0, wx.ALL | wx.EXPAND, 5) 65 | 66 | hbox = wx.BoxSizer(wx.HORIZONTAL) 67 | hbox.Add(add, 0, wx.ALL | wx.EXPAND, 5) 68 | hbox.Add(delete, 0, wx.ALL | wx.EXPAND, 5) 69 | hbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 70 | hbox.Add(close, 0, wx.ALL | wx.EXPAND, 5) 71 | hbox.Add(graph, 0, wx.ALL | wx.EXPAND, 5) 72 | 73 | vbox = wx.BoxSizer(wx.VERTICAL) 74 | vbox.AddSpacer(5) 75 | vbox.Add(hlistbox, 1, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 76 | vbox.AddSpacer(5) 77 | vbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 0) 78 | vbox.Add(hbox, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 79 | 80 | panel.SetSizer(vbox) 81 | 82 | self.read_list() 83 | 84 | def read_list(self): 85 | try: 86 | self.list.DeleteAllItems() 87 | except: 88 | pass 89 | 90 | self.listsave = [] 91 | 92 | if not self.conf.has_option('SPI', 'value_' + str(self.edit)): 93 | temp_list = [[0, 0], [1023, 1023]] 94 | self.conf.set('SPI', 'value_' + str(self.edit), str(temp_list)) 95 | self.conf.read() 96 | 97 | data = self.conf.get('SPI', 'value_' + str(self.edit)) 98 | try: 99 | temp_list = eval(data) 100 | except: 101 | temp_list = [] 102 | for ii in temp_list: 103 | self.list.Append([str(int(ii[0])), str(ii[1])]) 104 | self.listsave.append(ii) 105 | 106 | def on_delete(self, e): 107 | selected = self.list.GetFirstSelected() 108 | if selected == -1: 109 | self.parent.ShowMessage(_('nothing selected')) 110 | return 111 | 112 | temp_list = [] 113 | index = 0 114 | for i in self.listsave: 115 | if not index == selected: 116 | temp_list.append(i) 117 | index += 1 118 | 119 | self.conf.set('SPI', 'value_' + str(self.edit), str(temp_list)) 120 | self.read_list() 121 | 122 | def on_add(self, e): 123 | r = self.rawvalue.GetValue() 124 | u = self.unitvalue.GetValue() 125 | try: 126 | r = float(r) 127 | u = float(u) 128 | if r != float(int(r)): 129 | self.parent.ShowMessage(_('adc value must be a number without dec point')) 130 | return 131 | except: 132 | self.parent.ShowMessage(_('value isn\'t a number')) 133 | return 134 | 135 | self.listsave.append([r, u]) 136 | 137 | temp_list = [] 138 | for i in sorted(self.listsave, key=lambda item: (item[0])): 139 | temp_list.append(i) 140 | 141 | self.conf.set('SPI', 'value_' + str(self.edit), str(temp_list)) 142 | self.read_list() 143 | 144 | def on_graph(self, e): 145 | subprocess.Popen(['python', self.parent.currentpath+'/show_raw_adc_convert.py', str(self.edit)]) 146 | 147 | def on_close(self, e): 148 | self.Destroy() 149 | -------------------------------------------------------------------------------- /classes/bme280.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #-------------------------------------- 3 | # ___ ___ _ ____ 4 | # / _ \/ _ \(_) __/__ __ __ 5 | # / , _/ ___/ /\ \/ _ \/ // / 6 | # /_/|_/_/ /_/___/ .__/\_, / 7 | # /_/ /___/ 8 | # 9 | # bme280.py 10 | # Read data from a digital pressure sensor. 11 | # 12 | # Official datasheet available from : 13 | # https://www.bosch-sensortec.com/bst/products/all_products/bme280 14 | # 15 | # Author : Matt Hawkins 16 | # Date : 25/07/2016 17 | # 18 | # http://www.raspberrypi-spy.co.uk/ 19 | # 20 | #-------------------------------------- 21 | import smbus 22 | import time 23 | from ctypes import c_short 24 | from ctypes import c_byte 25 | from ctypes import c_ubyte 26 | 27 | class Bme280: 28 | def __init__(self,address): 29 | 30 | self.DEVICE = int(address, 16) # Default device I2C address 31 | 32 | self.bus = smbus.SMBus(1) # Rev 2 Pi, Pi 2 & Pi 3 uses bus 1 33 | # Rev 1 Pi uses bus 0 34 | 35 | def getShort(self,data, index): 36 | # return two bytes from data as a signed 16-bit value 37 | return c_short((data[index+1] << 8) + data[index]).value 38 | 39 | def getUShort(self,data, index): 40 | # return two bytes from data as an unsigned 16-bit value 41 | return (data[index+1] << 8) + data[index] 42 | 43 | def getChar(self,data,index): 44 | # return one byte from data as a signed char 45 | result = data[index] 46 | if result > 127: 47 | result -= 256 48 | return result 49 | 50 | def getUChar(self,data,index): 51 | # return one byte from data as an unsigned char 52 | result = data[index] & 0xFF 53 | return result 54 | 55 | def readBME280ID(self): 56 | # Chip ID Register Address 57 | addr=self.DEVICE 58 | REG_ID = 0xD0 59 | (chip_id, chip_version) = self.bus.read_i2c_block_data(addr, REG_ID, 2) 60 | return (chip_id, chip_version) 61 | 62 | def readBME280All(self): 63 | # Register Addresses 64 | addr=self.DEVICE 65 | REG_DATA = 0xF7 66 | REG_CONTROL = 0xF4 67 | REG_CONFIG = 0xF5 68 | 69 | REG_CONTROL_HUM = 0xF2 70 | REG_HUM_MSB = 0xFD 71 | REG_HUM_LSB = 0xFE 72 | 73 | # Oversample setting - page 27 74 | OVERSAMPLE_TEMP = 2 75 | OVERSAMPLE_PRES = 2 76 | MODE = 1 77 | 78 | # Oversample setting for humidity register - page 26 79 | OVERSAMPLE_HUM = 2 80 | self.bus.write_byte_data(addr, REG_CONTROL_HUM, OVERSAMPLE_HUM) 81 | 82 | control = OVERSAMPLE_TEMP<<5 | OVERSAMPLE_PRES<<2 | MODE 83 | self.bus.write_byte_data(addr, REG_CONTROL, control) 84 | 85 | # Read blocks of calibration data from EEPROM 86 | # See Page 22 data sheet 87 | cal1 = self.bus.read_i2c_block_data(addr, 0x88, 24) 88 | cal2 = self.bus.read_i2c_block_data(addr, 0xA1, 1) 89 | cal3 = self.bus.read_i2c_block_data(addr, 0xE1, 7) 90 | 91 | # Convert byte data to word values 92 | dig_T1 = self.getUShort(cal1, 0) 93 | dig_T2 = self.getShort(cal1, 2) 94 | dig_T3 = self.getShort(cal1, 4) 95 | 96 | dig_P1 = self.getUShort(cal1, 6) 97 | dig_P2 = self.getShort(cal1, 8) 98 | dig_P3 = self.getShort(cal1, 10) 99 | dig_P4 = self.getShort(cal1, 12) 100 | dig_P5 = self.getShort(cal1, 14) 101 | dig_P6 = self.getShort(cal1, 16) 102 | dig_P7 = self.getShort(cal1, 18) 103 | dig_P8 = self.getShort(cal1, 20) 104 | dig_P9 = self.getShort(cal1, 22) 105 | 106 | dig_H1 = self.getUChar(cal2, 0) 107 | dig_H2 = self.getShort(cal3, 0) 108 | dig_H3 = self.getUChar(cal3, 2) 109 | 110 | dig_H4 = self.getChar(cal3, 3) 111 | dig_H4 = (dig_H4 << 24) >> 20 112 | dig_H4 = dig_H4 | (self.getChar(cal3, 4) & 0x0F) 113 | 114 | dig_H5 = self.getChar(cal3, 5) 115 | dig_H5 = (dig_H5 << 24) >> 20 116 | dig_H5 = dig_H5 | (self.getUChar(cal3, 4) >> 4 & 0x0F) 117 | 118 | dig_H6 = self.getChar(cal3, 6) 119 | 120 | # Wait in ms (Datasheet Appendix B: Measurement time and current calculation) 121 | wait_time = 1.25 + (2.3 * OVERSAMPLE_TEMP) + ((2.3 * OVERSAMPLE_PRES) + 0.575) + ((2.3 * OVERSAMPLE_HUM)+0.575) 122 | time.sleep(wait_time/1000) # Wait the required time 123 | 124 | # Read temperature/pressure/humidity 125 | data = self.bus.read_i2c_block_data(addr, REG_DATA, 8) 126 | pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4) 127 | temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4) 128 | hum_raw = (data[6] << 8) | data[7] 129 | 130 | #Refine temperature 131 | var1 = ((((temp_raw>>3)-(dig_T1<<1)))*(dig_T2)) >> 11 132 | var2 = (((((temp_raw>>4) - (dig_T1)) * ((temp_raw>>4) - (dig_T1))) >> 12) * (dig_T3)) >> 14 133 | t_fine = var1+var2 134 | temperature = float(((t_fine * 5) + 128) >> 8); 135 | 136 | # Refine pressure and adjust for temperature 137 | var1 = t_fine / 2.0 - 64000.0 138 | var2 = var1 * var1 * dig_P6 / 32768.0 139 | var2 = var2 + var1 * dig_P5 * 2.0 140 | var2 = var2 / 4.0 + dig_P4 * 65536.0 141 | var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0 142 | var1 = (1.0 + var1 / 32768.0) * dig_P1 143 | if var1 == 0: 144 | pressure=0 145 | else: 146 | pressure = 1048576.0 - pres_raw 147 | pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1 148 | var1 = dig_P9 * pressure * pressure / 2147483648.0 149 | var2 = pressure * dig_P8 / 32768.0 150 | pressure = pressure + (var1 + var2 + dig_P7) / 16.0 151 | 152 | # Refine humidity 153 | humidity = t_fine - 76800.0 154 | humidity = (hum_raw - (dig_H4 * 64.0 + dig_H5 / 16384.0 * humidity)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * humidity * (1.0 + dig_H3 / 67108864.0 * humidity))) 155 | humidity = humidity * (1.0 - dig_H1 * humidity / 524288.0) 156 | if humidity > 100: 157 | humidity = 100 158 | elif humidity < 0: 159 | humidity = 0 160 | 161 | return temperature/100.0,pressure/100.0,humidity/100.0 162 | ''' 163 | def main(): 164 | bme = Bme280() 165 | 166 | (chip_id, chip_version) = bme.readBME280ID() 167 | print "Chip ID :", chip_id 168 | print "Version :", chip_version 169 | 170 | temperature,pressure,humidity = bme.readBME280All() 171 | 172 | print "Temperature : ", temperature, "C" 173 | print "Pressure : ", pressure, "hPa" 174 | print "Humidity : ", humidity, "%" 175 | 176 | if __name__=="__main__": 177 | main() 178 | ''' -------------------------------------------------------------------------------- /classes/check_vessel_self.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import os 18 | import requests 19 | import subprocess 20 | import time 21 | import json 22 | 23 | class checkVesselSelf: 24 | def __init__(self, conf): 25 | 26 | home = conf.home 27 | op_folder = conf.get('GENERAL', 'op_folder') 28 | currentpath = home+op_folder+'/openplotter' 29 | 30 | if not self.util_process_exist('signalk-server'): 31 | print 'Signal K starting' 32 | subprocess.call(['pkill', '-f', 'SK-base_d.py']) 33 | time.sleep(1) 34 | subprocess.Popen(['bin/signalk-server','-c',home+'/.openplotter','-s','openplotter-settings.json'],cwd=home+op_folder+'/signalk-server-node') 35 | starttime = time.time() 36 | error = True 37 | while starttime + 10 > time.time() and error: 38 | error = False 39 | time.sleep(0.2) 40 | try: 41 | response = requests.get('http://localhost:3000/signalk/v1/api/vessels/self') 42 | except: 43 | error = True 44 | subprocess.Popen(['python', currentpath + '/SK-base_d.py']) 45 | time.sleep(1) 46 | try: 47 | with open(home+'/.openplotter/openplotter-settings.json') as data_file: 48 | data = json.load(data_file) 49 | except: 50 | data = [] 51 | print "Error: Can't open file "+home+"/.openplotter/openplotter-settings.json" 52 | 53 | raw_uuid = data['vessel']['uuid'] 54 | self.mmsi = raw_uuid.split(':')[-1] 55 | self.uuid = 'urn:mrn:imo:mmsi:'+self.mmsi 56 | 57 | 58 | def util_process_exist(self, process_name): 59 | pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] 60 | exist = False 61 | for pid in pids: 62 | try: 63 | if process_name in open(os.path.join('/proc', pid, 'cmdline'), 'rb').read(): 64 | exist = True 65 | except IOError: # proc has already terminated 66 | continue 67 | return exist 68 | -------------------------------------------------------------------------------- /classes/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import ConfigParser, os 18 | 19 | class Conf: 20 | def __init__(self): 21 | self.home = os.path.expanduser('~') 22 | if 'root' in self.home: 23 | self.home = '/home/'+os.path.expanduser(os.environ["SUDO_USER"]) 24 | self.conf_folder = self.home+'/.openplotter' 25 | self.data_conf = ConfigParser.SafeConfigParser() 26 | self.read() 27 | 28 | def read(self): 29 | self.data_conf.read(self.conf_folder+'/openplotter.conf') 30 | 31 | def write(self): 32 | with open(self.conf_folder+'/openplotter.conf', 'wb') as configfile: 33 | self.data_conf.write(configfile) 34 | 35 | def get(self, section, item): 36 | result = '' 37 | try: 38 | result = self.data_conf.get(section, item) 39 | except ConfigParser.NoSectionError: 40 | self.read() 41 | try: 42 | self.data_conf.add_section(section) 43 | except ConfigParser.DuplicateSectionError: pass 44 | self.data_conf.set(section, item, '') 45 | self.write() 46 | except ConfigParser.NoOptionError: 47 | self.set(section, item, '') 48 | return result 49 | 50 | def set(self, section, item, value): 51 | self.read() 52 | try: 53 | self.data_conf.set(section, item, value) 54 | except ConfigParser.NoSectionError: 55 | self.data_conf.add_section(section) 56 | self.data_conf.set(section, item, value) 57 | self.write() 58 | 59 | def has_option(self, section, item): 60 | return self.data_conf.has_option(section, item) 61 | 62 | def has_section(self, section): 63 | return self.data_conf.has_section(section) 64 | 65 | def add_section(self, section): 66 | return self.data_conf.add_section(section) 67 | 68 | class Conf2: 69 | def __init__(self, file): 70 | self.home = os.path.expanduser('~') 71 | if 'root' in self.home: 72 | self.home = '/home/'+os.path.expanduser(os.environ["SUDO_USER"]) 73 | self.conf_file_path = self.home+'/.openplotter/'+file 74 | self.data_conf = ConfigParser.SafeConfigParser() 75 | if not os.path.isfile(self.conf_file_path): 76 | with open(self.conf_file_path,'w') as f: 77 | f.write('[GENERAL]') 78 | self.read() 79 | 80 | def read(self): 81 | self.data_conf.read(self.conf_file_path) 82 | 83 | def write(self): 84 | with open(self.conf_file_path, 'wb') as configfile: 85 | self.data_conf.write(configfile) 86 | 87 | def get(self, section, item): 88 | result = '' 89 | try: 90 | result = self.data_conf.get(section, item) 91 | except ConfigParser.NoSectionError: 92 | self.read() 93 | try: 94 | self.data_conf.add_section(section) 95 | except ConfigParser.DuplicateSectionError: pass 96 | self.data_conf.set(section, item, '') 97 | self.write() 98 | except ConfigParser.NoOptionError: 99 | self.set(section, item, '') 100 | return result 101 | 102 | def set(self, section, item, value): 103 | self.read() 104 | try: 105 | self.data_conf.set(section, item, value) 106 | except ConfigParser.NoSectionError: 107 | self.data_conf.add_section(section) 108 | self.data_conf.set(section, item, value) 109 | self.write() 110 | 111 | def has_option(self, section, item): 112 | return self.data_conf.has_option(section, item) 113 | 114 | def has_section(self, section): 115 | return self.data_conf.has_section(section) 116 | 117 | def add_section(self, section): 118 | return self.data_conf.add_section(section) 119 | -------------------------------------------------------------------------------- /classes/conf_analog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import ConfigParser, os 18 | 19 | class Conf_analog: 20 | def __init__(self): 21 | self.home = os.path.expanduser('~') 22 | if 'root' in self.home: 23 | self.home = '/home/'+os.path.expanduser(os.environ["SUDO_USER"]) 24 | self.conf_folder = self.home+'/.openplotter' 25 | self.data_conf = ConfigParser.SafeConfigParser() 26 | self.read() 27 | 28 | def read(self): 29 | self.data_conf.read(self.conf_folder+'/openplotter_analog.conf') 30 | 31 | def write(self): 32 | with open(self.conf_folder+'/openplotter_analog.conf', 'wb') as configfile: 33 | self.data_conf.write(configfile) 34 | 35 | def get(self,section,item): 36 | return self.data_conf.get(section,item) 37 | 38 | def getint(self,section,item): 39 | return self.data_conf.getint(section,item) 40 | 41 | def getfloat(self,section,item): 42 | return self.data_conf.getfloat(section,item) 43 | 44 | def has_option(self,section,item): 45 | return self.data_conf.has_option(section,item) 46 | 47 | def has_section(self,section): 48 | return self.data_conf.has_section(section) 49 | 50 | def add_section(self,section): 51 | return self.data_conf.add_section(section) 52 | 53 | def set(self,section,item,value): 54 | self.read() 55 | self.data_conf.set(section, item, value) 56 | self.write() 57 | -------------------------------------------------------------------------------- /classes/edit_i2c.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | import re 19 | 20 | from select_key import selectKey 21 | 22 | class editI2c(wx.Dialog): 23 | def __init__(self,name,magn,sk,rate,offset): 24 | 25 | title = _('Edit').decode('utf8')+(' '+name+' - '+magn).encode('utf-8') 26 | 27 | wx.Dialog.__init__(self, None, title=title, size=(450, 250)) 28 | 29 | panel = wx.Panel(self) 30 | 31 | titl = wx.StaticText(panel, label=_('Signal K key')) 32 | self.SKkey = wx.TextCtrl(panel, style=wx.CB_READONLY) 33 | self.SKkey.SetValue(sk) 34 | 35 | self.edit_skkey = wx.Button(panel, label=_('Edit')) 36 | self.edit_skkey.Bind(wx.EVT_BUTTON, self.onEditSkkey) 37 | 38 | self.clean_skkey = wx.Button(panel, label=_('Clean')) 39 | self.clean_skkey.Bind(wx.EVT_BUTTON, self.onCleanSkkey) 40 | 41 | hline1 = wx.StaticLine(panel) 42 | 43 | self.rate_list = ['0.1', '0.25', '0.5', '0.75', '1.0', '5.0', '30.0', '60.0', '300.0'] 44 | self.rate_label = wx.StaticText(panel, label=_('Rate (seconds)')) 45 | self.rate = wx.ComboBox(panel, choices=self.rate_list, style=wx.CB_READONLY) 46 | self.rate.SetValue(rate) 47 | 48 | hline2 = wx.StaticLine(panel) 49 | 50 | self.offset_label = wx.StaticText(panel, label=_('Offset')) 51 | self.offset = wx.TextCtrl(panel) 52 | self.offset.SetValue(offset) 53 | 54 | cancelBtn = wx.Button(panel, wx.ID_CANCEL) 55 | okBtn = wx.Button(panel, wx.ID_OK) 56 | 57 | hbox2 = wx.BoxSizer(wx.HORIZONTAL) 58 | hbox2.Add(self.clean_skkey, 0, wx.LEFT | wx.EXPAND, 5) 59 | hbox2.Add(self.edit_skkey, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 60 | 61 | hbox3 = wx.BoxSizer(wx.HORIZONTAL) 62 | hbox3.Add(self.rate_label, 0, wx.ALL | wx.EXPAND, 5) 63 | hbox3.Add(self.rate, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 64 | 65 | hbox4 = wx.BoxSizer(wx.HORIZONTAL) 66 | hbox4.Add(self.offset_label, 0, wx.ALL| wx.EXPAND, 5) 67 | hbox4.Add(self.offset, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 68 | 69 | hbox = wx.BoxSizer(wx.HORIZONTAL) 70 | hbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 5) 71 | hbox.Add(cancelBtn, 0, wx.ALL | wx.EXPAND, 5) 72 | hbox.Add(okBtn, 0, wx.ALL | wx.EXPAND, 5) 73 | 74 | vbox = wx.BoxSizer(wx.VERTICAL) 75 | vbox.AddSpacer(5) 76 | vbox.Add(titl, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 77 | vbox.Add(self.SKkey, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 78 | vbox.Add(hbox2, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 0) 79 | vbox.Add(hline1, 0, wx.ALL | wx.EXPAND, 5) 80 | vbox.Add(hbox3, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 0) 81 | vbox.Add(hline2, 0, wx.ALL | wx.EXPAND, 5) 82 | vbox.Add(hbox4, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 0) 83 | vbox.Add((0, 0), 1, wx.ALL | wx.EXPAND, 0) 84 | vbox.Add(hbox, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5) 85 | 86 | panel.SetSizer(vbox) 87 | self.panel = panel 88 | 89 | def onCleanSkkey(self,e): 90 | self.SKkey.SetValue('') 91 | 92 | def onEditSkkey(self,e): 93 | key = self.SKkey.GetValue() 94 | dlg = selectKey(key) 95 | 96 | res = dlg.ShowModal() 97 | if res == wx.ID_OK: 98 | key = dlg.keys_list.GetValue() 99 | if '*' in key: 100 | wildcard = dlg.wildcard.GetValue() 101 | if wildcard: 102 | if not re.match('^[0-9a-zA-Z]+$', wildcard): 103 | self.ShowMessage(_('Failed. * must contain only allowed characters.')) 104 | dlg.Destroy() 105 | return 106 | key = key.replace('*',wildcard) 107 | else: 108 | self.ShowMessage(_('Failed. You have to provide a name for *.')) 109 | dlg.Destroy() 110 | return 111 | dlg.Destroy() 112 | self.SKkey.SetValue(key) 113 | 114 | def ShowMessage(self, w_msg): 115 | wx.MessageBox(w_msg, 'Info', wx.OK | wx.ICON_INFORMATION) 116 | 117 | 118 | -------------------------------------------------------------------------------- /classes/getkeys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import json 18 | from conf import Conf 19 | 20 | class GetKeys: 21 | def __init__(self): 22 | conf = Conf() 23 | home = conf.home 24 | keys = [] 25 | 26 | try: 27 | with open(home+'/.config/signalk-server-node/node_modules/@signalk/signalk-schema/dist/keyswithmetadata.json') as data_file: 28 | data = json.load(data_file) 29 | except: 30 | #old signalk 31 | with open(home+'/.config/signalk-server-node/node_modules/@signalk/signalk-schema/src/keyswithmetadata.json') as data_file: 32 | data = json.load(data_file) 33 | for i in data: 34 | if '/vessels/*/' in i: 35 | key = i.replace('/vessels/*/','') 36 | key = key.replace('RegExp','*') 37 | key = key.replace('/','.') 38 | if data[i].has_key('description'): description = data[i]['description'] 39 | else: description = '[missing]' 40 | if data[i].has_key('units'): units = data[i]['units'] 41 | else: units = '' 42 | keys.append([key,description,units]) 43 | list_tmp = [] 44 | groups = [_('ungrouped')] 45 | ungrouped = [] 46 | for i in keys: 47 | items=i[0].split('.') 48 | if not items[0] in list_tmp: 49 | list_tmp.append(items[0]) 50 | else: 51 | if not items[0] in groups: 52 | groups.append(items[0]) 53 | for i in list_tmp: 54 | if not i in groups: ungrouped.append(i) 55 | 56 | self.keys = sorted(keys) 57 | self.groups = sorted(groups) 58 | self.ungrouped = sorted(ungrouped) -------------------------------------------------------------------------------- /classes/gmailbot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # This file is part of Openplotter. 3 | # Copyright (C) 2015 by sailoog 4 | # 5 | # Openplotter is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # any later version. 9 | # Openplotter is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with Openplotter. If not, see . 16 | 17 | import smtplib 18 | from email.mime.text import MIMEText 19 | 20 | class GmailBot: 21 | def __init__(self, GMAIL_USERNAME,GMAIL_PASSWORD,recipient): 22 | self.SMTP_SERVER = 'smtp.gmail.com' 23 | self.SMTP_PORT = 587 24 | self.GMAIL_USERNAME = GMAIL_USERNAME 25 | self.GMAIL_PASSWORD = GMAIL_PASSWORD 26 | self.recipient = recipient 27 | 28 | def send(self,subject,body ): 29 | msg = MIMEText(body) 30 | msg['Subject'] = subject 31 | msg['From'] = self.GMAIL_USERNAME 32 | msg['To'] = self.recipient 33 | session = smtplib.SMTP(self.SMTP_SERVER, self.SMTP_PORT) 34 | session.starttls() 35 | session.login(self.GMAIL_USERNAME, self.GMAIL_PASSWORD) 36 | session.sendmail(self.GMAIL_USERNAME, self.recipient, msg.as_string()) 37 | session.quit() -------------------------------------------------------------------------------- /classes/language.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import gettext 18 | 19 | class Language: 20 | 21 | def __init__(self, conf): 22 | 23 | home = conf.home 24 | op_folder = conf.get('GENERAL', 'op_folder')+'/openplotter' 25 | locale_folder = home+op_folder+'/locale' 26 | language = conf.get('GENERAL', 'lang') 27 | 28 | gettext.install('openplotter', locale_folder, unicode=False) 29 | presLan_en = gettext.translation('openplotter', locale_folder, languages=['en']) 30 | presLan_ca = gettext.translation('openplotter', locale_folder, languages=['ca']) 31 | presLan_es = gettext.translation('openplotter', locale_folder, languages=['es']) 32 | presLan_fr = gettext.translation('openplotter', locale_folder, languages=['fr']) 33 | presLan_nl = gettext.translation('openplotter', locale_folder, languages=['nl']) 34 | presLan_de = gettext.translation('openplotter', locale_folder, languages=['de']) 35 | presLan_it = gettext.translation('openplotter', locale_folder, languages=['it']) 36 | presLan_eu = gettext.translation('openplotter', locale_folder, languages=['eu']) 37 | presLan_gl = gettext.translation('openplotter', locale_folder, languages=['gl']) 38 | 39 | if language=='en':presLan_en.install() 40 | if language=='ca':presLan_ca.install() 41 | if language=='es':presLan_es.install() 42 | if language=='fr':presLan_fr.install() 43 | if language=='nl':presLan_nl.install() 44 | if language=='de':presLan_de.install() 45 | if language=='it':presLan_it.install() 46 | if language=='eu':presLan_eu.install() 47 | if language=='gl':presLan_gl.install() 48 | -------------------------------------------------------------------------------- /classes/select_key.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx 18 | from getkeys import GetKeys 19 | 20 | 21 | class selectKey(wx.Dialog): 22 | def __init__(self, SKkey): 23 | wx.Dialog.__init__(self, None, title=_('Select Signal K key'), size=(430, 370)) 24 | 25 | group = _('ungrouped') 26 | if len(SKkey)>0: 27 | SKkeySP = SKkey.split('.') 28 | group = SKkeySP[0] 29 | 30 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 31 | panel = wx.Panel(self) 32 | 33 | self.keys = GetKeys() 34 | self.skkeys = self.keys.keys 35 | self.groups = self.keys.groups 36 | self.ungrouped = self.keys.ungrouped 37 | 38 | wx.StaticText(panel, label=_('Groups'), pos=(10, 10)) 39 | self.groups_list = wx.ComboBox(panel, choices=self.groups , style=wx.CB_READONLY, size=(250, 32), pos=(10, 30)) 40 | self.groups_list.Bind(wx.EVT_COMBOBOX, self.onSelect_group) 41 | self.group_description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(410, 50), pos=(10, 65)) 42 | self.group_description.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) 43 | self.groups_list.SetValue(group) 44 | 45 | self.list_sk_keys = [] 46 | wx.StaticText(panel, label=_('Keys'), pos=(10, 125)) 47 | self.keys_list = wx.ComboBox(panel, choices=self.list_sk_keys , style=wx.CB_READONLY, size=(410, 32), pos=(10, 145)) 48 | self.keys_list.Bind(wx.EVT_COMBOBOX, self.onSelect_key) 49 | self.key_description = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(410, 50), pos=(10, 180)) 50 | self.key_description.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVECAPTION)) 51 | 52 | self.wildcardlabel = wx.StaticText(panel, label=_('*'), pos=(10, 240)) 53 | self.wildcardlabel2 = wx.StaticText(panel, label=_('allowed characters: 0-9, a-z, A-Z'), pos=(150, 240)) 54 | self.wildcard = wx.TextCtrl(panel, size=(410, 30), pos=(10, 260)) 55 | 56 | cancelBtn = wx.Button(panel, wx.ID_CANCEL, pos=(120, 300)) 57 | okBtn = wx.Button(panel, wx.ID_OK, pos=(230, 300)) 58 | 59 | self.onSelect_group(0) 60 | 61 | if len(SKkey)>0: 62 | keylist=[] 63 | keylist.append(SKkey) 64 | index = 0 65 | for keystar in SKkeySP: 66 | if index != 0: 67 | SKkeySP[index]='*' 68 | newkey='' 69 | 70 | for keystar2 in SKkeySP: 71 | newkey+=keystar2+'.' 72 | keylist.append(newkey[:-1]) 73 | SKkeySP = SKkey.split('.') 74 | index+=1 75 | 76 | for keystar3 in self.list_sk_keys: 77 | if keystar3 in keylist: 78 | key = keystar3 79 | self.keys_list.SetValue(key) 80 | 81 | if '*' in key: 82 | keylist = key.split('.') 83 | for i in range(len(SKkeySP)): 84 | if keylist[i] == '*': 85 | self.wildcard.SetValue(SKkeySP[i]) 86 | 87 | def onSelect_group(self,e): 88 | selected = self.groups_list.GetValue() 89 | self.keys_list.Clear() 90 | if selected == _('ungrouped'): 91 | self.list_sk_keys = self.ungrouped 92 | self.group_description.SetValue(_('Ungrouped Signal K keys.')) 93 | else: 94 | tmp_list = [] 95 | for i in self.skkeys: 96 | if selected == i[0]: 97 | self.group_description.SetValue(i[1]) 98 | else: 99 | items=i[0].split('.') 100 | if selected == items[0]: 101 | tmp_list.append(i[0]) 102 | self.list_sk_keys = tmp_list 103 | self.keys_list.AppendItems(self.list_sk_keys) 104 | self.keys_list.SetSelection(0) 105 | self.onSelect_key(0) 106 | 107 | def onSelect_key(self,e): 108 | selected = self.keys_list.GetValue() 109 | for i in self.skkeys: 110 | if selected == i[0]: 111 | self.key_description.SetValue(i[1]) 112 | if '*' in selected: 113 | self.wildcardlabel.Enable() 114 | self.wildcardlabel2.Enable() 115 | self.wildcard.Enable() 116 | else: 117 | self.wildcardlabel.Disable() 118 | self.wildcardlabel2.Disable() 119 | self.wildcard.Disable() -------------------------------------------------------------------------------- /classes/twitterbot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | from twython import Twython 19 | 20 | class TwitterBot: 21 | 22 | def __init__(self, apiKey, apiSecret, accessToken, accessTokenSecret): 23 | self._apiKey = apiKey 24 | self._apiSecret = apiSecret 25 | self._accessToken = accessToken 26 | self._accessTokenSecret = accessTokenSecret 27 | 28 | def send(self, tweetStr): 29 | self.tweetStr = tweetStr 30 | api = Twython(self._apiKey,self._apiSecret,self._accessToken,self._accessTokenSecret) 31 | api.update_status(status=self.tweetStr) 32 | -------------------------------------------------------------------------------- /ctrl_actions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import sys, subprocess, wx 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | action=sys.argv[1] 23 | 24 | #see actions.py 25 | start_all_actions='ACT19' 26 | 27 | conf = Conf() 28 | currentpath = conf.home+conf.get('GENERAL', 'op_folder')+'/openplotter' 29 | 30 | Language(conf) 31 | 32 | triggers=[] 33 | data=conf.get('ACTIONS', 'triggers') 34 | try: 35 | triggers=eval(data) 36 | except:triggers=[] 37 | 38 | #stop all 39 | if action=='0': 40 | i=0 41 | for ii in triggers: 42 | templist=ii[4] 43 | start=0 44 | for iii in templist: 45 | if iii[0]==start_all_actions: 46 | start=1 47 | triggers[i][0]=start 48 | i=i+1 49 | conf.set('ACTIONS', 'triggers', str(triggers)) 50 | subprocess.call(['pkill', '-f', 'SK-base_d.py']) 51 | subprocess.Popen(['pkill', '-9', 'mpg123']) 52 | subprocess.Popen(['python', currentpath + '/SK-base_d.py']) 53 | 54 | #start all 55 | if action=='1': 56 | i=0 57 | for ii in triggers: 58 | triggers[i][0]=1 59 | i=i+1 60 | conf.set('ACTIONS', 'triggers', str(triggers)) 61 | subprocess.call(['pkill', '-f', 'SK-base_d.py']) 62 | subprocess.Popen(['python', currentpath + '/SK-base_d.py']) 63 | 64 | app = wx.App() 65 | 66 | if action=='0': 67 | wx.MessageBox(_('All actions have been stopped.'), 'Info', wx.OK | wx.ICON_INFORMATION) 68 | if action=='1': 69 | wx.MessageBox(_('All actions have been started.'), 'Info', wx.OK | wx.ICON_INFORMATION) 70 | 71 | sys.exit() -------------------------------------------------------------------------------- /diagnostic-N2K-output.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import wx, sys, socket, threading, time 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | class MyFrame(wx.Frame): 23 | 24 | def __init__(self): 25 | Quelle='127.0.0.1' # Adresse des eigenen Rechners 26 | Port=55560 27 | 28 | self.e_udp_sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) #s.o. 29 | self.e_udp_sock.bind( (Quelle,Port) ) 30 | self.e_udp_sock.settimeout(1) 31 | 32 | self.ttimer=20 33 | self.conf = Conf() 34 | self.home = self.conf.home 35 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 36 | 37 | Language(self.conf) 38 | print self.conf.get('GENERAL','lang') 39 | 40 | list_N2K_txt=[] 41 | self.list_N2K=[] 42 | with open(self.currentpath+'/classes/N2K_PGN.csv') as f: 43 | list_N2K_txt = [x.strip('\n\r').split(',') for x in f.readlines()] 44 | 45 | for ii in list_N2K_txt: 46 | pgn=int(ii[0]) 47 | self.list_N2K.append([pgn,ii[1]]) 48 | 49 | self.Buffer = [0] * 500 50 | self.Zustand=6 51 | self.list_iter=[] 52 | 53 | wx.Frame.__init__(self, None, title='diagnostic N2K output', size=(650,435)) 54 | self.Bind(wx.EVT_CLOSE, self.OnClose) 55 | panel = wx.Panel(self, wx.ID_ANY) 56 | 57 | self.timer = wx.Timer(self) 58 | self.Bind(wx.EVT_TIMER, self.timer_act, self.timer) 59 | 60 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 61 | 62 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 63 | self.SetIcon(self.icon) 64 | 65 | self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER, size=(540, 370), pos=(5, 5)) 66 | self.list.InsertColumn(0, _('PGN'), wx.LIST_FORMAT_RIGHT, width=62) 67 | self.list.InsertColumn(1, _('SRC'), wx.LIST_FORMAT_RIGHT, width=38) 68 | self.list.InsertColumn(2, _('DST'), wx.LIST_FORMAT_RIGHT, width=38) 69 | self.list.InsertColumn(3, _('Name'), width=180) 70 | self.list.InsertColumn(4, _('Interval'), wx.LIST_FORMAT_RIGHT, width=45) 71 | self.list.InsertColumn(5, _('Data'), width=350) 72 | 73 | sort_SRC =wx.Button(panel, label=_('Sort SRC')) 74 | sort_SRC.Bind(wx.EVT_BUTTON, self.on_sort_SRC) 75 | 76 | sort_PGN =wx.Button(panel, label=_('Sort PGN')) 77 | sort_PGN.Bind(wx.EVT_BUTTON, self.on_sort_PGN) 78 | 79 | hlistbox = wx.BoxSizer(wx.HORIZONTAL) 80 | hlistbox.Add(self.list, 1, wx.ALL|wx.EXPAND, 5) 81 | 82 | hbox = wx.BoxSizer(wx.HORIZONTAL) 83 | hbox.Add(sort_SRC, 0, wx.RIGHT|wx.LEFT, 5) 84 | hbox.Add(sort_PGN, 0, wx.RIGHT|wx.LEFT, 5) 85 | 86 | vbox = wx.BoxSizer(wx.VERTICAL) 87 | vbox.Add(hlistbox, 1, wx.ALL|wx.EXPAND, 0) 88 | vbox.Add(hbox, 0, wx.ALL|wx.EXPAND, 0) 89 | panel.SetSizer(vbox) 90 | 91 | self.CreateStatusBar() 92 | 93 | self.Show(True) 94 | 95 | self.status='' 96 | self.data=[] 97 | 98 | self.timer.Start(self.ttimer) 99 | 100 | 101 | def timer_actx(self, event): 102 | pass 103 | 104 | def timer_act(self, event): 105 | self.timer.Stop() 106 | try: 107 | data1, addr = self.e_udp_sock.recvfrom( 512 ) 108 | except: 109 | self.timer.Start(self.ttimer) 110 | return 111 | # Die Puffergroesse muss immer eine Potenz 112 | # von 2 sein 113 | data=bytearray(data1) 114 | if data[7]+9==len(data): 115 | self.output(data) 116 | self.timer.Start(self.ttimer) 117 | 118 | def on_sort_PGN(self, e): 119 | self.timer.Stop() 120 | self.list_iter.sort() 121 | self.list.DeleteAllItems() 122 | self.init2() 123 | self.timer.Start(self.ttimer) 124 | 125 | def on_sort_SRC(self, e): 126 | self.timer.Stop() 127 | self.list.DeleteAllItems() 128 | 129 | list_new=[] 130 | for i in sorted(self.list_iter, key=lambda item: (item[1], item[0])): 131 | list_new.append(i) 132 | self.list_iter=list_new 133 | self.init2() 134 | self.timer.Start(self.ttimer) 135 | 136 | def init2(self): 137 | index=0 138 | for i in self.list_iter: 139 | self.list.InsertStringItem(index, str(i[0])) 140 | self.list.SetStringItem(index, 1, str(i[1])) 141 | self.list.SetStringItem(index, 2, str(i[2])) 142 | self.list.SetStringItem(index, 3, str(i[3])) 143 | self.list.SetStringItem(index, 4, str(i[4])) 144 | self.list.SetStringItem(index, 5, '') 145 | index+=1 146 | 147 | def OnClose(self, event): 148 | self.timer.Stop() 149 | self.Destroy() 150 | 151 | def output(self,data): 152 | k = 0 153 | Buffer=bytearray(data) 154 | if Buffer[0] == 0x94: 155 | nPriority = Buffer[2] 156 | lPGN=Buffer[3]+Buffer[4]*256+Buffer[5]*256*256 157 | nDestAddr = Buffer[6]; 158 | nSrcAddr = 'own' 159 | length = Buffer[7]; 160 | 161 | datap='' 162 | data=0 163 | for i in range(8,8+length): 164 | data=data+Buffer[i]; 165 | datap+=' '+('0'+hex(Buffer[i])[2:])[-2:] 166 | 167 | #print lPGN, nSrcAddr, nDestAddr, datap 168 | 169 | exist=0 170 | index=0 171 | tt=time.time() 172 | for i in self.list_iter: 173 | if nSrcAddr==i[1]: 174 | if lPGN==i[0]: 175 | td=round(i[4]*0.3+0.7*(tt-i[5]),1) 176 | self.list_iter[index][4]=td 177 | self.list_iter[index][5]=tt 178 | self.list.SetStringItem(index,4,str(td)) 179 | self.list.SetStringItem(index,5,str(datap)) 180 | self.Update() 181 | exist=1 182 | index+=1 183 | if exist==0: 184 | self.list.InsertStringItem(index, str(lPGN)) 185 | self.list.SetStringItem(index, 1, str(nSrcAddr)) 186 | self.list.SetStringItem(index, 2, str(nDestAddr)) 187 | for ii in self.list_N2K: 188 | if lPGN==ii[0]: 189 | self.list.SetStringItem(index, 3, ii[1]) 190 | self.list.SetStringItem(index, 4, 'X') 191 | self.list.SetStringItem(index, 5, datap) 192 | self.list_iter.append([lPGN,nSrcAddr,nDestAddr,self.list.GetItem(index, 3).GetText(),0,tt]) 193 | 194 | app = wx.App() 195 | MyFrame().Show() 196 | app.MainLoop() -------------------------------------------------------------------------------- /diagnostic-NMEA.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import wx, sys, socket, threading, time, webbrowser 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | class MyFrame(wx.Frame): 23 | 24 | def __init__(self): 25 | self.ttimer=100 26 | 27 | self.conf = Conf() 28 | self.home = self.conf.home 29 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 30 | 31 | Language(self.conf) 32 | 33 | self.list_iter=[] 34 | 35 | titleadd='' 36 | if len(sys.argv)>2: 37 | titleadd=sys.argv[2] 38 | 39 | wx.Frame.__init__(self, None, title=titleadd, size=(650,435)) 40 | self.Bind(wx.EVT_CLOSE, self.OnClose) 41 | panel = wx.Panel(self, wx.ID_ANY) 42 | 43 | self.timer = wx.Timer(self) 44 | self.Bind(wx.EVT_TIMER, self.timer_act, self.timer) 45 | 46 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 47 | 48 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 49 | self.SetIcon(self.icon) 50 | 51 | self.logger = wx.TextCtrl(panel, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP|wx.LC_SORT_ASCENDING) 52 | 53 | self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER) 54 | self.list.InsertColumn(0, _('Device'), width=50) 55 | self.list.InsertColumn(1, _('Type'), width=50) 56 | self.list.InsertColumn(2, _('Interval'), wx.LIST_FORMAT_RIGHT, width=50) 57 | self.list.InsertColumn(3, _('Data'), width=500) 58 | 59 | self.button_pause =wx.Button(panel, label=_('Pause'), pos=(555, 160)) 60 | self.button_pause.Bind(wx.EVT_BUTTON, self.pause) 61 | 62 | sort =wx.Button(panel, label=_('Sort'), pos=(555, 200)) 63 | sort.Bind(wx.EVT_BUTTON, self.sort) 64 | 65 | nmea =wx.Button(panel, label=_('NMEA info'), pos=(555, 240)) 66 | nmea.Bind(wx.EVT_BUTTON, self.nmea_info) 67 | 68 | self.pause_all=0 69 | 70 | htextbox = wx.BoxSizer(wx.HORIZONTAL) 71 | htextbox.Add(self.logger, 1, wx.ALL|wx.EXPAND, 5) 72 | 73 | hlistbox = wx.BoxSizer(wx.HORIZONTAL) 74 | hlistbox.Add(self.list, 1, wx.ALL|wx.EXPAND, 5) 75 | 76 | hbox = wx.BoxSizer(wx.HORIZONTAL) 77 | hbox.Add(self.button_pause, 0, wx.RIGHT|wx.LEFT, 5) 78 | hbox.Add(sort, 0, wx.RIGHT|wx.LEFT, 5) 79 | hbox.Add(nmea, 0, wx.RIGHT|wx.LEFT, 5) 80 | 81 | vbox = wx.BoxSizer(wx.VERTICAL) 82 | vbox.Add(htextbox, 1, wx.ALL|wx.EXPAND, 0) 83 | vbox.Add(hlistbox, 1, wx.ALL|wx.EXPAND, 0) 84 | vbox.Add(hbox, 0, wx.ALL|wx.EXPAND, 0) 85 | panel.SetSizer(vbox) 86 | 87 | 88 | self.CreateStatusBar() 89 | 90 | self.Show(True) 91 | 92 | self.s2='' 93 | self.status='' 94 | self.data=[] 95 | self.baudc=0 96 | self.baud=0 97 | 98 | self.timer.Start(self.ttimer) 99 | 100 | def connect(self): 101 | port=10113 102 | try: 103 | if len(sys.argv)>0: 104 | port=int(sys.argv[1]) 105 | self.s2 = socket.socket() 106 | self.s2.connect(("localhost", port)) 107 | self.s2.settimeout(5) 108 | self.status= _('connected to:').decode('utf8')+str(port) 109 | except socket.error, error_msg: 110 | self.status= _('Failed to connect with localhost:10113. Error: ').decode('utf8')+ str(error_msg[0])+_(', trying to reconnect...') 111 | self.s2='' 112 | time.sleep(7) 113 | else: self.status='' 114 | 115 | def timer_act(self, event): 116 | frase_nmea_log='' 117 | if not self.s2: 118 | self.connect() 119 | else: 120 | frase_nmea='' 121 | self.timer.Stop() 122 | try: 123 | frase_nmea = self.s2.recv(1024) 124 | except Exception as ex: 125 | #except error_msg: 126 | # self.status= _('Connected with localhost:10110. Error: ')+ str(error_msg[0])+_(', waiting for data...') 127 | template = "An exception of type {0} occured. Arguments:\n{1!r}" 128 | self.status = template.format(type(ex).__name__, ex.args) 129 | self.SetStatusText(self.status) 130 | 131 | else: 132 | if frase_nmea and self.pause_all==0: 133 | self.baud+=10*len(frase_nmea) 134 | tt=time.time() 135 | 136 | if self.baudc+1 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import subprocess, platform 19 | 20 | if platform.machine()[0:3]!='arm': 21 | print 'this is not a raspberry pi -> no RPI display settings' 22 | else: 23 | output = subprocess.check_output(['tvservice', '-d', '/dev/stdout']) 24 | output = output[:128] 25 | try: 26 | editfile = open('edid.dat', 'r', 5000) 27 | bak = editfile.read() 28 | editfile.close() 29 | except: 30 | bak = '' 31 | 32 | if output != bak: 33 | subprocess.check_output(['tvservice', '-d', 'edid.dat']) 34 | output = subprocess.check_output(['edidparser', 'edid.dat']) 35 | 36 | DisplayResolution = '' 37 | 38 | if '800x480' in output: 39 | DisplayResolution = '800 480' 40 | #DisplayResolution = '1024 600' 41 | #DisplayResolution = '1120 630' 42 | elif '1024:600' in output: 43 | DisplayResolution = '1024 600' 44 | elif '1280:800' in output: 45 | DisplayResolution = '1280 800' 46 | 47 | if DisplayResolution != '': 48 | configfile = open('/boot/config.txt', 'r', 5000) 49 | data = configfile.read() 50 | configfile.close() 51 | output = subprocess.check_output(['tvservice', '-n']) 52 | output = output[12:-1] 53 | if ('[EDID=' + output) in data: pass 54 | else: 55 | if '[all]' in data: 56 | line = data.split('\n') 57 | data = '' 58 | for l in line: 59 | if '[all]' in l: 60 | data += '[EDID=' + output + ']\n' 61 | data += 'hdmi_group=2\n' 62 | data += 'hdmi_mode=87\n' 63 | data += 'hdmi_cvt='+ DisplayResolution +' 60 6 0 0 0\n' 64 | data += l+'\n' 65 | else: 66 | data += '[EDID=' + output + ']\n' 67 | data += 'hdmi_group=2\n' 68 | data += 'hdmi_mode=87\n' 69 | data += 'hdmi_cvt='+ DisplayResolution +' 60 6 0 0 0\n' 70 | data += '[all]\n' 71 | configfile = open('/boot/config.txt', 'w') 72 | configfile.write(data) 73 | configfile.close() 74 | -------------------------------------------------------------------------------- /docs/openplotter-documentation-en.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/docs/openplotter-documentation-en.pdf -------------------------------------------------------------------------------- /emulator/GPIO.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | BCM=1 19 | PUD_DOWN=False 20 | PUD_UP=False 21 | IN=False 22 | 23 | 24 | class GPIO(): 25 | pass 26 | 27 | def setmode(x): 28 | pass 29 | def setwarnings(x): 30 | pass 31 | def setup(x,y,z): 32 | pass 33 | def output(self, x,y): 34 | pass 35 | -------------------------------------------------------------------------------- /emulator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/emulator/__init__.py -------------------------------------------------------------------------------- /emulator/w1thermsensor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | THERM_SENSOR_DS18B20=10 19 | 20 | class W1ThermSensor(): 21 | test=0 22 | 23 | def setmode(x): 24 | pass 25 | def setwarnings(x): 26 | pass 27 | def setup(x,y,z): 28 | pass 29 | def output(self, x,y): 30 | pass 31 | -------------------------------------------------------------------------------- /keyword: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # This file is part of Openplotter. 3 | # Copyright (C) 2015 by sailoog 4 | # 5 | # Openplotter is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # any later version. 9 | # Openplotter is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with Openplotter. If not, see . 16 | 17 | import socket, sys 18 | 19 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 20 | 21 | def sendSK(keyword,source): 22 | try: 23 | keyword = keyword.replace('"', "'") 24 | source = source.replace('"', "'") 25 | path='notifications.keyword' 26 | SignalK='{"updates":[{"$source":"OPnotifications.keyword.'+source+'","values":[{"path":"'+path+'","value":"'+keyword+'"}]}]}\n' 27 | sock.sendto(SignalK, ('127.0.0.1', 55558)) 28 | except Exception,e: print str(e) 29 | 30 | try: 31 | keyword=sys.argv[1] 32 | except: 33 | keyword='null' 34 | source='undefined' 35 | sendSK(keyword,source) 36 | else: 37 | try: 38 | source=sys.argv[2] 39 | except: 40 | source='undefined' 41 | sendSK(keyword,source) 42 | else: 43 | sendSK(keyword,source) 44 | -------------------------------------------------------------------------------- /locale/ca/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/ca/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/de/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/de/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/en/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/es/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/es/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/eu/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/eu/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/fr/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/fr/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/gl/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/gl/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/it/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/it/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /locale/nl/LC_MESSAGES/openplotter.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/locale/nl/LC_MESSAGES/openplotter.mo -------------------------------------------------------------------------------- /message.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import wx, sys 19 | from classes.language import Language 20 | from classes.conf import Conf 21 | 22 | text=sys.argv[1] 23 | lang=sys.argv[2] 24 | 25 | class MyFrame(wx.Frame): 26 | def __init__(self, parent): 27 | conf = Conf() 28 | Language(conf) 29 | wx.Frame.__init__(self, parent) 30 | dlg = wx.MessageDialog(self, text, _('Message'), wx.OK | wx.ICON_WARNING) 31 | dlg.ShowModal() 32 | sys.exit() 33 | 34 | app = wx.App(False) 35 | frame = MyFrame(None) 36 | app.MainLoop() -------------------------------------------------------------------------------- /mqtt_d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # This file is part of Openplotter. 3 | # Copyright (C) 2015 by sailoog 4 | # 5 | # Openplotter is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 2 of the License, or 8 | # any later version. 9 | # Openplotter is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with Openplotter. If not, see . 16 | 17 | import paho.mqtt.client as paho 18 | import socket 19 | from classes.conf import Conf 20 | 21 | def on_message(client, userdata, msg): 22 | try: 23 | for i in topics_list: 24 | if msg.topic == i[0]: 25 | if i[1] == 0: #general 26 | path='notifications.'+msg.topic 27 | value = msg.payload 28 | value = value.replace('"', "'") 29 | SignalK='{"updates":[{"$source":"OPnotifications.MQTT.'+msg.topic+'","values":[{"path":"'+path+'","value":"'+value+'"}]}]}\n' 30 | sock.sendto(SignalK, ('127.0.0.1', 55558)) 31 | if i[1] == 1: #signal k key input 32 | path = i[2] 33 | value = msg.payload 34 | value = value.replace('"', "'") 35 | SignalK='{"updates":[{"$source":"OPsensors.MQTT.'+msg.topic+'","values":[{"path":"'+path+'","value":"'+value+'"}]}]}\n' 36 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 37 | if i[1] == 2: #signal k delta input 38 | SignalK = msg.payload 39 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 40 | except Exception,e: print str(e) 41 | 42 | def on_connect(client, userdata, flags, rc): 43 | try: 44 | for i in topics_list: 45 | client.subscribe(i[0], qos=0) 46 | except Exception,e: print str(e) 47 | 48 | conf = Conf() 49 | 50 | x=conf.get('MQTT', 'topics') 51 | if x: topics_list=eval(x) 52 | else: topics_list=[] 53 | 54 | local_broker='127.0.0.1' 55 | local_port='1883' 56 | user=conf.get('MQTT', 'username') 57 | passw=conf.get('MQTT', 'password') 58 | broker=conf.get('MQTT', 'broker') 59 | port=conf.get('MQTT', 'port') 60 | client='' 61 | client_local='' 62 | 63 | if user and passw and topics_list: 64 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 65 | if broker and port: 66 | client = paho.Client() 67 | client.on_message = on_message 68 | client.on_connect = on_connect 69 | client.username_pw_set(user, passw) 70 | try: 71 | client.connect(broker, port) 72 | client.loop_start() 73 | except Exception,e: print str(e) 74 | client_local = paho.Client() 75 | client_local.on_message = on_message 76 | client_local.on_connect = on_connect 77 | client_local.username_pw_set(user, passw) 78 | client_local.connect(local_broker, local_port) 79 | client_local.loop_forever() 80 | -------------------------------------------------------------------------------- /openplotter.conf: -------------------------------------------------------------------------------- 1 | [GENERAL] 2 | version = 0.17.1 3 | state = stable 4 | repository = openplotter 5 | lang = en 6 | # openplotter installation path relative to home 7 | op_folder = /.config 8 | 9 | [AIS-SDR] 10 | enable = 0 11 | gain = 12 | ppm = 13 | channel = a 14 | band = 15 | gsm_channel = 16 | 17 | [NMEA0183] 18 | sentences = 19 | 20 | [STARTUP] 21 | delay = 0 22 | opencpn = 0 23 | opencpn_no_opengl = 0 24 | opencpn_fullscreen = 1 25 | kplex = 1 26 | x11vnc = 1 27 | vnc_pass = 0 28 | gps_time = 1 29 | maximize = 30 | play = 1 31 | sound = /home/pi/.config/openplotter/sounds/Store_Door_Chime.mp3 32 | node_red = 1 33 | 34 | [CALCULATE] 35 | mag_var = 0 36 | mag_var_rate = 37 | mag_var_accuracy = 38 | hdt = 0 39 | hdt_dev = 0 40 | hdt_rate = 41 | hdt_accuracy = 42 | rot = 0 43 | rot_rate = 44 | rot_accuracy = 45 | tw_stw = 0 46 | tw_sog = 0 47 | tw_rate = 48 | tw_accuracy = 49 | 50 | [N2K] 51 | enable = 0 52 | can_usb = 53 | pgn_output = 54 | pgn_generate = 55 | output = 0 56 | 57 | [WIFI] 58 | enable = 1 59 | ip = 10.10.10.1 60 | device = wlan0 61 | share = 0 62 | ssid = OpenPlotter 63 | password = 12345678 64 | hw_mode = g 65 | channel = 6 66 | wpa = 2 67 | bridge = 0 68 | 69 | [GPIO] 70 | sensors = 71 | 72 | [TWITTER] 73 | enable = 0 74 | apikey = 75 | apisecret = 76 | accesstoken = 77 | accesstokensecret = 78 | 79 | [GMAIL] 80 | enable = 0 81 | gmail = 82 | password = 83 | recipient = 84 | 85 | [ACTIONS] 86 | triggers = 87 | 88 | [1W] 89 | ds18b20 = 90 | 91 | [UDEV] 92 | usbinst = 93 | 94 | [SMS] 95 | enable = 0 96 | serial = 0 97 | bluetooth = 98 | connection = 99 | enable_sending = 0 100 | phone = 101 | 102 | [MQTT] 103 | broker = 104 | port = 105 | username = 106 | password = 107 | topics = 108 | 109 | [I2C] 110 | sensors = 111 | 112 | [COMPASS] 113 | rate = 114 | magnetic_h = 115 | heel = 116 | pitch = 117 | deviation = [[0, 0], [10, 10], [20, 20], [30, 30], [40, 40], [50, 50], [60, 60], [70, 70], [80, 80], [90, 90], [100, 100], [110, 110], [120, 120], [130, 130], [140, 140], [150, 150], [160, 160], [170, 170], [180, 180], [190, 190], [200, 200], [210, 210], [220, 220], [230, 230], [240, 240], [250, 250], [260, 260], [270, 270], [280, 280], [290, 290], [300, 300], [310, 310], [320, 320], [330, 330], [340, 340], [350, 350], [360, 360]] 118 | variation = 119 | 120 | [SPI] 121 | mcp = [[0, 0, '', '', 0], [0, 1, '', '', 0], [0, 2, '', '', 0], [0, 3, '', '', 0], [0, 4, '', '', 0], [0, 5, '', '', 0], [0, 6, '', '', 0], [0, 7, '', '', 0]] 122 | 123 | [TOOLS] 124 | py = [['Analog ads1115', 'put analog values to SignalK', 'analog_ads1115.py', '0'], ['Analog Firmata', 'put analog values to SignalK', 'oppymata.py', '0'], ['SignalK Simulator', 'change values with sliders and send values to SignalK', 'SK-simulator.py', '0'], ['Auto Setup', 'configure basic system', 'autosetup_tty.py', '1']] 125 | 126 | -------------------------------------------------------------------------------- /openplotter.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/openplotter.ico -------------------------------------------------------------------------------- /openplotter_debug.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/openplotter_debug.ico -------------------------------------------------------------------------------- /show_deviation_table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import matplotlib.pyplot as plt 18 | import sys 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | conf = Conf() 23 | Language(conf) 24 | 25 | data = conf.get('COMPASS', 'deviation') 26 | listsave = [] 27 | try: 28 | listsave = eval(data) 29 | except: 30 | listsave = [] 31 | 32 | x=[] 33 | y=[] 34 | for ii in listsave: 35 | x.append(ii[1] - ii[0]) 36 | y.append(ii[0]) 37 | 38 | plt.plot(x,y) 39 | plt.suptitle(_('Show deviation table as curve'), fontsize=12) 40 | plt.xlabel(_('Deviation'), fontsize=12) 41 | plt.ylabel(_('Compass Heading'), fontsize=12) 42 | plt.show() 43 | 44 | -------------------------------------------------------------------------------- /show_raw_adc_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import matplotlib.pyplot as plt 18 | import sys 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | edit = sys.argv[1] 23 | 24 | conf = Conf() 25 | Language(conf) 26 | data = conf.get('SPI', 'value_' + str(edit)) 27 | listsave = [] 28 | try: 29 | temp_list = eval(data) 30 | except: 31 | temp_list = [] 32 | for ii in temp_list: 33 | listsave.append(ii) 34 | plt.plot(*zip(*listsave)) 35 | plt.suptitle( 36 | _('settings to convert raw adc values (unlinear and/or no factor and/or no offset)\n to useable values for input ').decode('utf8') + str( 37 | edit), fontsize=12) 38 | plt.xlabel(_('row adc value'), fontsize=12) 39 | plt.ylabel(_('value in unit'), fontsize=12) 40 | plt.show() 41 | 42 | -------------------------------------------------------------------------------- /sounds/Alien_Siren.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Alien_Siren.mp3 -------------------------------------------------------------------------------- /sounds/Annoying_Alarm_Clock.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Annoying_Alarm_Clock.mp3 -------------------------------------------------------------------------------- /sounds/BOMB_SIREN.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/BOMB_SIREN.mp3 -------------------------------------------------------------------------------- /sounds/Beep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Beep.mp3 -------------------------------------------------------------------------------- /sounds/Bleep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Bleep.mp3 -------------------------------------------------------------------------------- /sounds/Busy_Signal.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Busy_Signal.mp3 -------------------------------------------------------------------------------- /sounds/Buzz_Fade_In.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Buzz_Fade_In.mp3 -------------------------------------------------------------------------------- /sounds/Buzz_Fade_Out.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Buzz_Fade_Out.mp3 -------------------------------------------------------------------------------- /sounds/Dog_Whistle.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Dog_Whistle.mp3 -------------------------------------------------------------------------------- /sounds/Door_Buzzer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Door_Buzzer.mp3 -------------------------------------------------------------------------------- /sounds/Door_entry_notification.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Door_entry_notification.mp3 -------------------------------------------------------------------------------- /sounds/Eas_Beep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Eas_Beep.mp3 -------------------------------------------------------------------------------- /sounds/Fire_Alarm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Fire_Alarm.mp3 -------------------------------------------------------------------------------- /sounds/Fire_pager.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Fire_pager.mp3 -------------------------------------------------------------------------------- /sounds/High_Pitch_Dog_Whistle.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/High_Pitch_Dog_Whistle.mp3 -------------------------------------------------------------------------------- /sounds/House_Fire_Alarm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/House_Fire_Alarm.mp3 -------------------------------------------------------------------------------- /sounds/Intruder_Alert.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Intruder_Alert.mp3 -------------------------------------------------------------------------------- /sounds/Japanese_Temple_Bell_Small.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Japanese_Temple_Bell_Small.mp3 -------------------------------------------------------------------------------- /sounds/Loud_Alarm_Clock_Buzzer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Loud_Alarm_Clock_Buzzer.mp3 -------------------------------------------------------------------------------- /sounds/Metronome.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Metronome.mp3 -------------------------------------------------------------------------------- /sounds/Plectron_tones.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Plectron_tones.mp3 -------------------------------------------------------------------------------- /sounds/Rooster.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Rooster.mp3 -------------------------------------------------------------------------------- /sounds/Rooster_Crow.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Rooster_Crow.mp3 -------------------------------------------------------------------------------- /sounds/Rooster_Crowing.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Rooster_Crowing.mp3 -------------------------------------------------------------------------------- /sounds/School_Fire_Alarm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/School_Fire_Alarm.mp3 -------------------------------------------------------------------------------- /sounds/Ship_Bell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Ship_Bell.mp3 -------------------------------------------------------------------------------- /sounds/Ship_Brass_Bell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Ship_Brass_Bell.mp3 -------------------------------------------------------------------------------- /sounds/Siren.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Siren.mp3 -------------------------------------------------------------------------------- /sounds/Siren_Noise.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Siren_Noise.mp3 -------------------------------------------------------------------------------- /sounds/Smoke_Alarm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Smoke_Alarm.mp3 -------------------------------------------------------------------------------- /sounds/Store_Door_Chime.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Store_Door_Chime.mp3 -------------------------------------------------------------------------------- /sounds/Temple_Bell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Temple_Bell.mp3 -------------------------------------------------------------------------------- /sounds/Temple_Bell_Huge.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Temple_Bell_Huge.mp3 -------------------------------------------------------------------------------- /sounds/Tornado_Siren_II.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Tornado_Siren_II.mp3 -------------------------------------------------------------------------------- /sounds/Warning_Siren.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Warning_Siren.mp3 -------------------------------------------------------------------------------- /sounds/Woop_Woop.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/Woop_Woop.mp3 -------------------------------------------------------------------------------- /sounds/mandatory_evacuation.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/mandatory_evacuation.mp3 -------------------------------------------------------------------------------- /sounds/railroad_crossing_bell.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sailoog/openplotter/b91343abf9d3f1928849b639701ea6d7917a169e/sounds/railroad_crossing_bell.mp3 -------------------------------------------------------------------------------- /test_sms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This file is part of Openplotter. 5 | # Copyright (C) 2015 by sailoog 6 | # 7 | # Openplotter is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # any later version. 11 | # Openplotter is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with Openplotter. If not, see . 18 | 19 | import wx, sys, subprocess, gammu 20 | from classes.conf import Conf 21 | from classes.language import Language 22 | 23 | class MainFrame(wx.Frame): 24 | 25 | def __init__(self): 26 | 27 | self.option=sys.argv[1] 28 | self.text_sms=sys.argv[2] 29 | self.text_sms=unicode(self.text_sms,'utf-8') 30 | self.phone=sys.argv[3] 31 | 32 | self.conf = Conf() 33 | self.home = self.conf.home 34 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 35 | 36 | Language(self.conf) 37 | 38 | wx.Frame.__init__(self, None, title=_('Test SMS'), size=(500,260)) 39 | 40 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 41 | 42 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 43 | self.SetIcon(self.icon) 44 | 45 | self.CreateStatusBar() 46 | 47 | self.text=wx.StaticText(self, label=_('Error'), pos=(10, 10)) 48 | 49 | self.output = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP, size=(480,110), pos=(10,50)) 50 | 51 | self.button_close =wx.Button(self, label=_('Close'), pos=(300, 170)) 52 | self.Bind(wx.EVT_BUTTON, self.close, self.button_close) 53 | 54 | self.button_calculate =wx.Button(self, label=_('Start'), pos=(400, 170)) 55 | self.Bind(wx.EVT_BUTTON, self.calculate, self.button_calculate) 56 | 57 | if self.option=='i': 58 | self.text.SetLabel(_('Press start to check the settings and connect to the GSM device')) 59 | 60 | if self.option=='t': 61 | self.text.SetLabel(_('Press start to send the text "').decode('utf8')+self.text_sms+_('"\nto the number "').decode('utf8')+self.phone+'"') 62 | 63 | self.Centre() 64 | 65 | def calculate(self,e): 66 | self.output.SetValue('') 67 | output='' 68 | if self.option=='i': 69 | self.SetStatusText(_('Connecting...')) 70 | try: 71 | output=subprocess.check_output(['gammu', 'identify']) 72 | except: output= _('Error opening device. Check settings.') 73 | if self.option=='t': 74 | self.SetStatusText(_('Sending...')) 75 | try: 76 | sm = gammu.StateMachine() 77 | sm.ReadConfig() 78 | sm.Init() 79 | netinfo = sm.GetNetworkInfo() 80 | output+= 'Network name: %s' % netinfo['NetworkName'] 81 | output+= '\nNetwork code: %s' % netinfo['NetworkCode'] 82 | output+= '\nLAC: %s' % netinfo['LAC'] 83 | output+= '\nCID: %s' % netinfo['CID'] 84 | message = { 85 | 'Text': self.text_sms, 86 | 'SMSC': {'Location': 1}, 87 | 'Number': self.phone, 88 | } 89 | sm.SendSMS(message) 90 | output+='\nSMS "'+self.text_sms+_('" sent succesfully to ').decode('utf8')+self.phone 91 | except Exception,e: output= str(e) 92 | 93 | self.output.SetValue(output) 94 | self.SetStatusText(_('Finished')) 95 | 96 | def close(self,e): 97 | self.Destroy() 98 | 99 | if __name__ == "__main__": 100 | app = wx.App() 101 | MainFrame().Show() 102 | app.MainLoop() -------------------------------------------------------------------------------- /time_gps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import socket, pynmea2, subprocess 19 | from classes.conf import Conf 20 | from classes.language import Language 21 | 22 | fecha='' 23 | hora='' 24 | foundtime = False 25 | 26 | conf = Conf() 27 | Language(conf) 28 | 29 | try: 30 | sock_in = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 31 | sock_in.settimeout(10) 32 | sock_in.connect(('127.0.0.1', 10109)) 33 | except socket.error, error_msg: 34 | print _('Failed to connect with localhost:10109.') 35 | print _('Error: ').decode('utf8')+ str(error_msg[0]) 36 | else: 37 | cont = 0 38 | while foundtime == False: 39 | frase_nmea ='' 40 | try: 41 | frase_nmea = sock_in.recv(1024) 42 | except socket.error, error_msg: 43 | try: 44 | print _('Failed to connect with localhost:10109.') 45 | print _('Error: ').decode('utf8')+ str(error_msg[0]) 46 | sys.stdout.flush() 47 | except: pass 48 | break 49 | else: 50 | if frase_nmea: 51 | try: 52 | nmea_list=frase_nmea.split() 53 | 54 | for i in nmea_list: 55 | msg = pynmea2.parse(i) 56 | nmea_type=msg.sentence_type 57 | if nmea_type == 'RMC': 58 | fecha = msg.datestamp 59 | hora = msg.timestamp 60 | foundtime = True 61 | break 62 | else: 63 | cont=cont+1 64 | except: pass 65 | if cont >= 30: break 66 | 67 | if fecha and hora: 68 | subprocess.call([ 'date', '--set', fecha.strftime('%Y-%m-%d'), '--utc']) 69 | subprocess.call([ 'date', '--set', hora.strftime('%H:%M:%S'), '--utc']) 70 | print _('Date and time retrieved from NMEA data successfully.') 71 | else: 72 | print _('Unable to retrieve date or time from NMEA data.') 73 | -------------------------------------------------------------------------------- /tools/NMEA_0183_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import wx, os, sys, subprocess 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from conf import Conf 23 | from language import Language 24 | from add_NMEA_0183 import addNMEA_0183 25 | 26 | class MyFrame(wx.Frame): 27 | 28 | def __init__(self): 29 | 30 | self.conf = Conf() 31 | self.home = self.conf.home 32 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 33 | 34 | Language(self.conf) 35 | 36 | wx.Frame.__init__(self, None, title=_('NMEA 0183 generator'), size=(690,350)) 37 | 38 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 39 | 40 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 41 | self.SetIcon(self.icon) 42 | 43 | wx.StaticBox(self, label=_(' NMEA 0183 '), size=(670, 230), pos=(10, 10)) 44 | self.list_nmea = wx.ListCtrl(self, style=wx.LC_REPORT, size=(565, 200), pos=(15, 30)) 45 | self.list_nmea.InsertColumn(0, _('Sentence'), width=100) 46 | self.list_nmea.InsertColumn(1, _('Rate'), width=50) 47 | self.list_nmea.InsertColumn(2, _('Fields'), width=1500) 48 | 49 | self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.edit_nmea, self.list_nmea) 50 | 51 | self.add_nmea_button =wx.Button(self, label=_('add'), pos=(585, 30)) 52 | self.Bind(wx.EVT_BUTTON, self.add_nmea, self.add_nmea_button) 53 | 54 | self.delete_nmea_button =wx.Button(self, label=_('delete'), pos=(585, 65)) 55 | self.Bind(wx.EVT_BUTTON, self.delete_nmea, self.delete_nmea_button) 56 | 57 | self.compat_nmea_button =wx.Button(self, label=_('opencpn\ndefault'), pos=(585, 189)) 58 | self.Bind(wx.EVT_BUTTON, self.compat_nmea, self.compat_nmea_button) 59 | 60 | self.diagnostic_nmea_button=wx.Button(self, label=_('NMEA Diagnostic'), pos=(10, 250)) 61 | self.Bind(wx.EVT_BUTTON, self.kplex_diagnostic, self.diagnostic_nmea_button) 62 | 63 | self.diagnostic_sk_button=wx.Button(self, label=_('SK Diagnostic'), pos=(180, 250)) 64 | self.Bind(wx.EVT_BUTTON, self.sk_diagnostic, self.diagnostic_sk_button) 65 | 66 | 67 | self.CreateStatusBar() 68 | 69 | self.Centre() 70 | 71 | self.Show(True) 72 | 73 | self.read_sentences() 74 | 75 | 76 | def start_d(self): 77 | subprocess.call(['pkill', '-f', 'SK-base_d.py']) 78 | subprocess.Popen(['python',self.currentpath+'/SK-base_d.py']) 79 | 80 | 81 | def read_sentences(self): 82 | self.sentences=[] 83 | self.list_nmea.DeleteAllItems() 84 | data=self.conf.get('NMEA0183', 'sentences') 85 | try: 86 | temp_list=eval(data) 87 | except:temp_list=[] 88 | for ii in temp_list: 89 | self.sentences.append(ii) 90 | fields=',' 91 | for i in ii[1]: 92 | if type(i) is str: fields+=i+',' 93 | elif type(i) is list: 94 | fields+=i[1]+',' 95 | self.list_nmea.Append([ii[0],ii[2],fields]) 96 | 97 | 98 | def edit_nmea(self,e): 99 | selected_sentence=e.GetIndex() 100 | edit=[selected_sentence,self.sentences[selected_sentence]] 101 | self.edit_add_nmea(edit) 102 | 103 | def add_nmea(self,e): 104 | self.edit_add_nmea(0) 105 | 106 | def edit_add_nmea(self,edit): 107 | self.SetStatusText('') 108 | dlg = addNMEA_0183(edit, self.conf) 109 | res = dlg.ShowModal() 110 | if res == wx.ID_OK: 111 | nmea=dlg.nmea 112 | if not nmea[0]: return 113 | if edit==0: 114 | fields=',' 115 | for i in nmea[1]: 116 | if type(i) is str: fields+=i+',' 117 | elif type(i) is list: 118 | fields+=i[1]+',' 119 | self.list_nmea.Append([nmea[0],nmea[2],fields]) 120 | self.sentences.append([nmea[0],nmea[1],nmea[2]]) 121 | else: 122 | self.list_nmea.SetStringItem(edit[0],0,nmea[0]) 123 | self.list_nmea.SetStringItem(edit[0],1,str(nmea[2])) 124 | fields=',' 125 | for i in nmea[1]: 126 | if type(i) is str: fields+=i+',' 127 | elif type(i) is list: 128 | fields+=i[1]+',' 129 | self.list_nmea.SetStringItem(edit[0],2,fields) 130 | self.sentences[edit[0]][0]=nmea[0] 131 | if '[' in nmea[1]: nmea[1]=eval(nmea[1]) 132 | self.sentences[edit[0]][1]=nmea[1] 133 | self.sentences[edit[0]][2]=nmea[2] 134 | self.conf.set('NMEA0183', 'sentences', str(self.sentences)) 135 | self.start_d() 136 | dlg.Destroy() 137 | 138 | def delete_nmea(self,e): 139 | self.SetStatusText('') 140 | selected_sentence=self.list_nmea.GetFirstSelected() 141 | if selected_sentence==-1: 142 | self.SetStatusText('Select a sentence to delete.') 143 | return 144 | del self.sentences[selected_sentence] 145 | self.list_nmea.DeleteItem(selected_sentence) 146 | self.conf.set('NMEA0183', 'sentences', str(self.sentences)) 147 | self.start_d() 148 | 149 | def compat_nmea(self,e): 150 | if self.list_nmea.GetItemCount()>0: 151 | self.SetStatusText(_('This function is only allowed when the list is empty.')) 152 | return 153 | self.conf.set('NMEA0183', 'sentences', "[['HDG', [['navigation.headingMagnetic', 'x.x|deg', '+', 0.0], '', '', '', ''], 0.5], ['XDR', ['A', ['navigation.attitude.roll', 'x.x|deg', '+', 0.0], 'D', 'ROLL'], 1.0], ['XDR', ['A', ['navigation.attitude.pitch', 'x.x|deg', '+', 0.0], 'D', 'PTCH'], 1.0], ['XDR', ['P', ['environment.outside.pressure', 'x.xxxx', '/', 100000.0], 'B', 'Barometer'], 5.0], ['XDR', ['C', ['environment.outside.temperature', 'x.x|C', '+', 0.0], 'C', 'ENV_OUTAIR_T'], 5.0], ['MTW', [['environment.water.temperature', 'x.x|C', '+', 0.0], 'C'], 5.0]]") 154 | self.start_d() 155 | self.read_sentences() 156 | 157 | def kplex_diagnostic(self,e): 158 | wx.MessageBox('use diagnostic on NMEA0183\nselect system\npush diagnostic', 'Info', wx.OK | wx.ICON_INFORMATION) 159 | 160 | def sk_diagnostic(self,e): 161 | subprocess.call(['pkill', '-f', 'diagnostic-SK-input.py']) 162 | subprocess.Popen(['python',self.currentpath+'/diagnostic-SK-input.py']) 163 | 164 | app = wx.App() 165 | MyFrame().Show() 166 | app.MainLoop() -------------------------------------------------------------------------------- /tools/NMEA_2000_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import wx, os, sys 18 | from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from conf import Conf 23 | from language import Language 24 | 25 | class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin): 26 | def __init__(self, parent, height): 27 | wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER, size=(565, height)) 28 | CheckListCtrlMixin.__init__(self) 29 | ListCtrlAutoWidthMixin.__init__(self) 30 | 31 | class MyFrame(wx.Frame): 32 | def __init__(self): 33 | self.conf = Conf() 34 | self.home = self.conf.home 35 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 36 | Language(self.conf) 37 | 38 | wx.Frame.__init__(self, None, title=_('Generate N2K from Signal K'), size=(630, 300)) 39 | self.Bind(wx.EVT_CLOSE, self.when_closed) 40 | #self.SetAutoLayout(1) 41 | #self.SetupScrolling() 42 | 43 | self.icon = wx.Icon(self.currentpath + '/openplotter.ico', wx.BITMAP_TYPE_ICO) 44 | self.SetIcon(self.icon) 45 | 46 | self.panel = wx.Panel(self) 47 | 48 | self.list_N2Kgen = [ 49 | ['126992','System Time',''], 50 | ['127245','Rudder','steering.rudderAngle.value'], 51 | ['127250','Heading','navigation.headingMagnetic.value'], 52 | ['127257','Attitude','navigation.attitude.pitch.value, navigation.attitude.roll.value, navigation.attitude.yaw.value'], 53 | ['127488','Engine_Rapid','propulsion.port.revolutions.value'], 54 | ['127488_1','Engine_Rapid','propulsion.starboard.revolutions.value'], 55 | ['127489','Engine','propulsion.port.oilTemperature.value, propulsion.port.temperature.value'], 56 | ['127489_1','Engine','propulsion.starboard.oilTemperature.value, propulsion.starboard.temperature.value'], 57 | ['127505','FluidLevel','tanks.fuel.standard.capacity.value, tanks.fuel.standard.currentLevel.value'], 58 | ['127505_1','FluidLevel','tanks.liveWell.standard.capacity.value, tanks.liveWell.standard.currentLevel.value'], 59 | ['127505_2','FluidLevel','tanks.wasteWater.standard.capacity.value, tanks.wasteWater.standard.currentLevel.value'], 60 | ['127505_3','FluidLevel','tanks.blackWater.standard.capacity.value, tanks.blackWater.standard.currentLevel.value'], 61 | ['127508','Battery_Status','DC Electrical Properties.dcSource.voltage.value, DC Electrical Properties.dcSource.current.value, DC Electrical Properties.dcSource.temperature.value'], 62 | ['128259','Speed','navigation.speedOverGround.value, navigation.speedThroughWater.value'], 63 | ['128267','Depth','environment.depth.belowTransducer.value, environment.depth.surfaceToTransducer.value'], 64 | ['128275','Distance_Log','navigation.log.value, navigation.logTrip.value'], 65 | ['129025','Position_Rapid','navigation.position.latitude, navigation.position.longitude'], 66 | ['129026','COG_SOG','navigation.courseOverGroundTrue.value, navigation.speedOverGround.value'], 67 | ['130306_2','Wind Data','environment.wind.angleApparent.value, environment.wind.speedApparent.value'], 68 | ['130306_3','Wind Data','environment.wind.angleTrueWater.value, environment.wind.speedTrue.value'], 69 | ['130310','Environmental_Parameters','environment.outside.pressure.value, environment.outside.temperature.value, environment.water.temperature.value'], 70 | ['130311','Environmental_Parameters','environment.outside.pressure.value, environment.inside.humidity.value, environment.water.temperature.value'], 71 | ['130316','Temperature','environment.inside.refrigerator.temperature.value'], 72 | ['130316_1','Temperature','propulsion.port.exhaustTemperature.value'] 73 | ] 74 | 75 | self.list_N2K = CheckListCtrl(self.panel, 100) 76 | self.list_N2K.InsertColumn(0, _('PGN'), width=100) 77 | self.list_N2K.InsertColumn(1, _('description'), width=250) 78 | self.list_N2K.InsertColumn(2, _('Signal K variable'), width=920) 79 | self.list_N2K.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_selected) 80 | 81 | OK = wx.Button(self.panel, label=_('OK')) 82 | OK.Bind(wx.EVT_BUTTON, self.on_OK) 83 | 84 | hlistbox = wx.BoxSizer(wx.HORIZONTAL) 85 | hlistbox.Add(self.list_N2K, 1, wx.ALL | wx.EXPAND, 5) 86 | 87 | vbox = wx.BoxSizer(wx.VERTICAL) 88 | vbox.Add(hlistbox, 1, wx.ALL | wx.EXPAND, 0) 89 | vbox.Add(OK, 0, wx.ALL, 5) 90 | 91 | self.panel.SetSizer(vbox) 92 | 93 | for ii in self.list_N2Kgen: 94 | self.list_N2K.Append(ii) 95 | 96 | data = self.conf.get('N2K', 'pgn_generate') 97 | try: 98 | self.PGN_list = eval(data) 99 | except: 100 | self.PGN_list = [] 101 | i=0 102 | for ii in self.list_N2Kgen: 103 | if str(ii[0]) in self.PGN_list: 104 | self.list_N2K.CheckItem(i) 105 | i += 1 106 | 107 | 108 | def on_OK(self,e): 109 | result = [] 110 | i=0 111 | for ii in self.list_N2Kgen: 112 | if self.list_N2K.IsChecked(i): 113 | result.append(str(ii[0])) 114 | i += 1 115 | self.conf.set('N2K', 'pgn_generate', str(result)) 116 | 117 | self.when_closed(e) 118 | 119 | def on_selected(self,e): 120 | pass 121 | 122 | def when_closed(self,e): 123 | self.Destroy() 124 | 125 | 126 | app = wx.App() 127 | MyFrame().Show() 128 | app.MainLoop() -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # 2 | Standalone tools 3 | 4 | OpenPlotter has a chance to integrate independent programs which can share some of the OpenPlotter features. This was done to be open for add-ons done by advanced users and to keep OpenPlotter simple for newcomers. 5 | 6 | There are implemented some standalone tools in OpenPlotter core maintaned by developers and a demo tool to make it easier to start. You can look at the code of these tools and build your own app/addon. 7 | 8 | ### Adding a tool 9 | 10 | Openplotter is able to work with external Python scripts. 11 | 12 | There is a demo script in *~/.openplotter/tools/demo_tool.py* 13 | 14 | To enable the demo tool open the OpenPlotter configuration file in *~/.openplotter/openplotter.conf*. Go to section [TOOLS] and you will see something like this: 15 | 16 | ``` 17 | [TOOLS] 18 | py = [['Analog ads1115', 'put analog values to SignalK', 'analog_ads1115.py', '0'], ['Analog Firmata', 'put analog values to SignalK', 'oppymata.py', '0'], ['SignalK Simulator', 'change values with sliders and send values to SignalK', 'SK-simulator.py', '0'], ['Auto Setup', 'configure basic system', 'autosetup_tty.py', '0']] 19 | ``` 20 | 21 | The syntax of this array is: 22 | 23 | ``` 24 | [TOOLS] 25 | py = [['title', 'description', 'file.py', 'startup'], [...], [...], [...]] 26 | ``` 27 | 28 | * **title** is the name you want to have in OpenPlotter Tools menu. 29 | * **description** is a short sentence describing your app. 30 | * **file.py** is the name of the file where your app lives. 31 | * **startup** will be '1' if you want your app to start at startup or '0' if not. 32 | 33 | To enable the demo tool you have to add this array to the array _py_ in the [TOOLS] section of *~/.openplotter/openplotter.conf* file: 34 | 35 | ``` 36 | ['Demo tool', 'You can use this app to start your own apps', 'demo_tool.py', '0'] 37 | ``` 38 | 39 | Save the file and go to the OpenPlotter Tools menu. You should see now the option "Demo tool". 40 | 41 | Once selected, a new window will be open with these options: 42 | 43 | * **Settings**. If you have defined a config file for your app, it will be open with a text editor. 44 | * **Start**. This option will start your app. 45 | * **Stop**. This option will stop your app. 46 | * **Cancel**. This option will close this window. 47 | 48 | If you want to add your own tools you have just to create a python script in *~/.openplotter/tools* folder and edit the [TOOLS] section in *~/.openplotter/openplotter.conf* file just the same way you did for the demo tool. 49 | 50 | See the source of the demo tool to know how to manage config files, manage the OpenPlotter config file, interact with Signal K server or access to OpenPlotter classes. 51 | 52 | Let us know if you make any tool that we can add to OpenPlotter core. 53 | 54 | -------------------------------------------------------------------------------- /tools/SDR_AIS_fine_cal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This file is part of Openplotter. 5 | # Copyright (C) 2015 by sailoog 6 | # 7 | # Openplotter is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # any later version. 11 | # Openplotter is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with Openplotter. If not, see . 18 | 19 | import wx, os, sys, subprocess 20 | 21 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 22 | sys.path.append(op_folder+'/classes') 23 | from conf import Conf 24 | from language import Language 25 | 26 | class MainFrame(wx.Frame): 27 | 28 | def __init__(self): 29 | 30 | self.option=sys.argv[1] 31 | 32 | self.conf = Conf() 33 | self.home = self.conf.home 34 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 35 | 36 | Language(self.conf) 37 | 38 | wx.Frame.__init__(self, None, title=_('Fine calibration'), size=(500,300)) 39 | 40 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 41 | 42 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 43 | self.SetIcon(self.icon) 44 | 45 | self.CreateStatusBar() 46 | 47 | self.text=wx.StaticText(self, label=_('Error'), pos=(10, 10)) 48 | 49 | self.gain=self.conf.get('AIS-SDR', 'gain') 50 | self.ppm=self.conf.get('AIS-SDR', 'ppm') 51 | self.channel=self.conf.get('AIS-SDR', 'gsm_channel') 52 | 53 | wx.StaticText(self, label=_('gain: ').decode('utf8')+self.gain, pos=(10, 70)) 54 | wx.StaticText(self, label=_('ppm: ').decode('utf8')+self.ppm, pos=(100, 70)) 55 | 56 | self.output = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP, size=(480,110), pos=(10,90)) 57 | 58 | self.button_close =wx.Button(self, label=_('Close'), pos=(300, 210)) 59 | self.Bind(wx.EVT_BUTTON, self.close, self.button_close) 60 | 61 | self.button_calculate =wx.Button(self, label=_('Calculate'), pos=(400, 210)) 62 | self.Bind(wx.EVT_BUTTON, self.calculate, self.button_calculate) 63 | 64 | if self.option=='c': 65 | self.text.SetLabel(_('Press Calculate and wait for the system to calculate the ppm value with\nthe selected channel. Put the obtained value in "Correction (ppm)" field\nand enable SDR-AISreception. Estimated time: 1 min.')) 66 | wx.StaticText(self, label=_('channel: ').decode('utf8')+self.channel, pos=(200, 70)) 67 | if self.option=='b': 68 | self.text.SetLabel(_('Press Calculate and wait for the system to check the band. Write down\nthe strongest channel (power). If you do not find any channel try another\nband. Estimated time: 5 min.')) 69 | 70 | self.Centre() 71 | 72 | def calculate(self,e): 73 | self.SetStatusText(_('Working...')) 74 | self.output.SetValue('') 75 | if self.option=='c': 76 | 77 | try: output=subprocess.check_output(['kal', '-c', self.channel, '-g', self.gain, '-e', self.ppm]) 78 | except: output=_('error') 79 | if self.option=='b': 80 | band=self.conf.get('AIS-SDR', 'band') 81 | try: output=subprocess.check_output(['kal', '-s', band, '-g', self.gain, '-e', self.ppm]) 82 | except: output=_('error') 83 | self.output.SetValue(output) 84 | self.SetStatusText(_('Finished')) 85 | 86 | def close(self,e): 87 | self.Destroy() 88 | 89 | if __name__ == "__main__": 90 | app = wx.App() 91 | MainFrame().Show() 92 | app.MainLoop() -------------------------------------------------------------------------------- /tools/SDR_AIS_waterfall.py: -------------------------------------------------------------------------------- 1 | # This file is part of pyrlsdr. 2 | # Copyright (C) 2013 by Roger 3 | # 4 | # pyrlsdr is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | 9 | # pyrlsdr is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with pyrlsdr. If not, see . 16 | 17 | 18 | from __future__ import division 19 | import matplotlib.animation as animation 20 | from matplotlib.mlab import psd 21 | import pylab as pyl 22 | import numpy as np 23 | import sys 24 | from rtlsdr import RtlSdr 25 | 26 | # A simple waterfall, spectrum plotter 27 | # 28 | # Controls: 29 | # 30 | # * Scroll mouse-wheel up or down, or press the left or right arrow keys, to 31 | # change the center frequency (hold shift for finer control). 32 | # * Press "+" and "-" to control gain, and space to enable AGC. 33 | # * Type a frequency (in MHz) and press enter to directly change the center frequency 34 | 35 | NFFT = 1024 36 | NUM_SAMPLES_PER_SCAN = NFFT*16 37 | NUM_BUFFERED_SWEEPS = 50 38 | 39 | # change this to control the number of scans that are combined in a single sweep 40 | # (e.g. 2, 3, 4, etc.) Note that it can slow things down 41 | NUM_SCANS_PER_SWEEP = 1 42 | 43 | # these are the increments when scrolling the mouse wheel or pressing '+' or '-' 44 | FREQ_INC_COARSE = 1e6 45 | FREQ_INC_FINE = 0.1e6 46 | GAIN_INC = 5 47 | 48 | class Waterfall(object): 49 | keyboard_buffer = [] 50 | shift_key_down = False 51 | image_buffer = -100*np.ones((NUM_BUFFERED_SWEEPS,\ 52 | NUM_SCANS_PER_SWEEP*NFFT)) 53 | 54 | def __init__(self, sdr=None, fig=None): 55 | self.fig = fig if fig else pyl.figure() 56 | self.sdr = sdr if sdr else RtlSdr() 57 | 58 | self.init_plot() 59 | 60 | def init_plot(self): 61 | self.ax = self.fig.add_subplot(1,1,1) 62 | self.image = self.ax.imshow(self.image_buffer, aspect='auto',\ 63 | interpolation='nearest', vmin=-50, vmax=10) 64 | self.ax.set_xlabel('Current frequency (MHz)') 65 | self.ax.get_yaxis().set_visible(False) 66 | 67 | self.fig.canvas.mpl_connect('scroll_event', self.on_scroll) 68 | self.fig.canvas.mpl_connect('key_press_event', self.on_key_press) 69 | self.fig.canvas.mpl_connect('key_release_event', self.on_key_release) 70 | self.fig.canvas.set_window_title('AIS signal') 71 | 72 | def update_plot_labels(self): 73 | fc = self.sdr.fc 74 | rs = self.sdr.rs 75 | freq_range = (fc - rs/2)/1e6, (fc + rs*(NUM_SCANS_PER_SWEEP - 0.5))/1e6 76 | 77 | self.image.set_extent(freq_range + (0, 1)) 78 | self.fig.canvas.draw_idle() 79 | 80 | def on_scroll(self, event): 81 | if event.button == 'up': 82 | self.sdr.fc += FREQ_INC_FINE if self.shift_key_down else FREQ_INC_COARSE 83 | self.update_plot_labels() 84 | elif event.button == 'down': 85 | self.sdr.fc -= FREQ_INC_FINE if self.shift_key_down else FREQ_INC_COARSE 86 | self.update_plot_labels() 87 | 88 | def on_key_press(self, event): 89 | if event.key == '+': 90 | self.sdr.gain += GAIN_INC 91 | elif event.key == '-': 92 | self.sdr.gain -= GAIN_INC 93 | elif event.key == ' ': 94 | self.sdr.gain = 'auto' 95 | elif event.key == 'shift': 96 | self.shift_key_down = True 97 | elif event.key == 'right': 98 | self.sdr.fc += FREQ_INC_FINE if self.shift_key_down else FREQ_INC_COARSE 99 | self.update_plot_labels() 100 | elif event.key == 'left': 101 | self.sdr.fc -= FREQ_INC_FINE if self.shift_key_down else FREQ_INC_COARSE 102 | self.update_plot_labels() 103 | elif event.key == 'enter': 104 | # see if valid frequency was entered, then change center frequency 105 | try: 106 | # join individual key presses into a string 107 | input = ''.join(self.keyboard_buffer) 108 | 109 | # if we're doing multiple adjacent scans, we need to figure out 110 | # the appropriate center freq for the leftmost scan 111 | center_freq = float(input)*1e6 + (self.sdr.rs/2)*(1 - NUM_SCANS_PER_SWEEP) 112 | self.sdr.fc = center_freq 113 | 114 | self.update_plot_labels() 115 | except ValueError: 116 | pass 117 | 118 | self.keyboard_buffer = [] 119 | else: 120 | self.keyboard_buffer.append(event.key) 121 | 122 | def on_key_release(self, event): 123 | if event.key == 'shift': 124 | self.shift_key_down = False 125 | 126 | def update(self, *args): 127 | # save center freq. since we're gonna be changing it 128 | start_fc = self.sdr.fc 129 | 130 | # prepare space in buffer 131 | # TODO: use indexing to avoid recreating buffer each time 132 | self.image_buffer = np.roll(self.image_buffer, 1, axis=0) 133 | 134 | for scan_num, start_ind in enumerate(range(0, NUM_SCANS_PER_SWEEP*NFFT, NFFT)): 135 | self.sdr.fc += self.sdr.rs*scan_num 136 | 137 | # estimate PSD for one scan 138 | samples = self.sdr.read_samples(NUM_SAMPLES_PER_SCAN) 139 | psd_scan, f = psd(samples, NFFT=NFFT) 140 | 141 | self.image_buffer[0, start_ind: start_ind+NFFT] = 10*np.log10(psd_scan) 142 | 143 | # plot entire sweep 144 | self.image.set_array(self.image_buffer) 145 | 146 | # restore original center freq. 147 | self.sdr.fc = start_fc 148 | 149 | return self.image, 150 | 151 | def start(self): 152 | self.update_plot_labels() 153 | if sys.platform == 'darwin': 154 | # Disable blitting. The matplotlib.animation's restore_region() 155 | # method is only implemented for the Agg-based backends, 156 | # which the macosx backend is not. 157 | blit = False 158 | else: 159 | blit = True 160 | ani = animation.FuncAnimation(self.fig, self.update, interval=50, 161 | blit=blit) 162 | 163 | pyl.show() 164 | 165 | return 166 | 167 | 168 | def main(): 169 | 170 | gin=sys.argv[1] 171 | ppm=sys.argv[2] 172 | chn=sys.argv[3] 173 | if ppm=='0': ppm='1' 174 | if chn=='a': frc=161.975e6 175 | if chn=='b': frc=162.025e6 176 | 177 | sdr = RtlSdr() 178 | wf = Waterfall(sdr) 179 | 180 | # some defaults 181 | sdr.rs = 1e6 182 | sdr.fc = frc 183 | sdr.gain = float(gin) 184 | sdr.freq_correction = int(float(ppm)) 185 | 186 | wf.start() 187 | 188 | # cleanup 189 | sdr.close() 190 | 191 | 192 | if __name__ == '__main__': 193 | main() 194 | -------------------------------------------------------------------------------- /tools/SK-simulator.conf: -------------------------------------------------------------------------------- 1 | [main] 2 | item_0 = [0, 'navigation.courseOverGroundTrue', 0, 0, 360, 0.0174533, 0] 3 | item_1 = [1, 'navigation.speedOverGround', 4, 0, 10, 0.5144441, 0] 4 | item_2 = [2, 'navigation.headingMagnetic', 0, 0, 360, 0.0174533, 0] 5 | item_3 = [3, 'environment.wind.angleApparent', 0, -180, 180, 0.0174533, 0] 6 | item_4 = [4, 'environment.wind.speedApparent', 4, 0, 40, 0.5144441, 0] 7 | item_5 = [5, 'environment.wind.angleTrueWater', 0, -180, 180, 0.0174533, 0] 8 | item_6 = [6, 'environment.wind.speedTrue', 4, 0, 40, 0.5144441, 0] 9 | item_7 = [7, 'environment.depth.belowTransducer', 4, 0, 40, 1, 0] -------------------------------------------------------------------------------- /tools/SK-simulator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2016 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import wx, os, sys, socket, time, ConfigParser, subprocess 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from conf import Conf 23 | from language import Language 24 | 25 | class MyFrame(wx.Frame): 26 | def __init__(self): 27 | self.conf = conf 28 | self.home = home 29 | self.currentpath = self.home+self.conf.get('GENERAL', 'op_folder')+'/openplotter' 30 | 31 | self.tick=0 32 | self.deg2rad=0.0174533 33 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 34 | 35 | self.Slider=[] 36 | self.Slider_v=[] 37 | self.HSlider=[] 38 | self.Slider_list=[] 39 | 40 | Language(self.conf) 41 | 42 | wx.Frame.__init__(self, None, title="SK-Simulator", size=(650,435)) 43 | self.Bind(wx.EVT_CLOSE, self.OnClose) 44 | self.panel = wx.Panel(self) 45 | self.vbox = wx.BoxSizer(wx.VERTICAL) 46 | 47 | self.ttimer=500 48 | self.timer = wx.Timer(self) 49 | self.Bind(wx.EVT_TIMER, self.timer_act, self.timer) 50 | 51 | self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) 52 | 53 | self.icon = wx.Icon(self.currentpath+'/openplotter.ico', wx.BITMAP_TYPE_ICO) 54 | self.SetIcon(self.icon) 55 | 56 | self.read_conf() 57 | 58 | #self.SK_Slider(0,'navigation.courseOverGroundTrue',0,0,360,self.deg2rad,0) 59 | for i in self.Slider_list: 60 | self.SK_Slider_conf(i[0],i[1],i[2],i[3],i[4],i[5],i[6]) 61 | 62 | self.Bind(wx.EVT_CHECKBOX, self.on_change_checkbox) 63 | 64 | allBtn = wx.Button(self.panel, label=_('all'),size=(70, 32), pos=(450, 360)) 65 | allBtn.Bind(wx.EVT_BUTTON, self.allBtn) 66 | 67 | noneBtn = wx.Button(self.panel, label=_('none'),size=(70, 32), pos=(550, 360)) 68 | noneBtn.Bind(wx.EVT_BUTTON, self.noneBtn) 69 | 70 | HButton = wx.BoxSizer(wx.HORIZONTAL) 71 | HButton.Add((0,0), 1, wx.ALL|wx.EXPAND, 5) 72 | HButton.Add(noneBtn, 0, wx.ALL|wx.EXPAND, 5) 73 | HButton.Add(allBtn, 0, wx.ALL|wx.EXPAND, 5) 74 | 75 | self.vbox.Add((0,0), 1, wx.ALL|wx.EXPAND, 5) 76 | self.vbox.Add(HButton, 0, wx.ALL|wx.EXPAND, 5) 77 | self.panel.SetSizer(self.vbox) 78 | 79 | self.Centre() 80 | 81 | self.Show(True) 82 | 83 | self.timer.Start(self.ttimer) 84 | 85 | 86 | def SK_Slider(self,index,get_label,get_start,get_min,get_max,get_factor,get_offset): 87 | self.Slider.append([]) 88 | self.Slider_v.append([]) 89 | self.HSlider.append([]) 90 | self.Slider_list.append([index,get_label,get_start,get_min,get_max,get_factor,get_offset,False]) 91 | self.Slider[index]= wx.CheckBox(self.panel, label=get_label) 92 | 93 | self.Slider_v[index] = wx.Slider(self.panel, -1, get_start, get_min, get_max, (-1,-1), (250, -1), wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_VALUE_LABEL) 94 | 95 | self.HSlider[index] = wx.BoxSizer(wx.HORIZONTAL) 96 | self.HSlider[index].Add(self.Slider[index], 0, wx.ALL|wx.EXPAND, 5) 97 | self.HSlider[index].Add((0,0), 1, wx.ALL|wx.EXPAND, 0) 98 | self.HSlider[index].Add(self.Slider_v[index], 0, wx.ALL|wx.EXPAND, 5) 99 | self.vbox.Add(self.HSlider[index], 0, wx.ALL|wx.EXPAND, 5) 100 | 101 | def SK_Slider_conf(self,index,get_label,get_start,get_min,get_max,get_factor,get_offset): 102 | self.Slider.append([]) 103 | self.Slider_v.append([]) 104 | self.HSlider.append([]) 105 | self.Slider[index]= wx.CheckBox(self.panel, label=get_label) 106 | 107 | self.Slider_v[index] = wx.Slider(self.panel, -1, get_start, get_min, get_max, (-1,-1), (250, -1), wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_VALUE_LABEL) 108 | 109 | self.HSlider[index] = wx.BoxSizer(wx.HORIZONTAL) 110 | self.HSlider[index].Add(self.Slider[index], 0, wx.ALL|wx.EXPAND, 5) 111 | self.HSlider[index].Add((0,0), 1, wx.ALL|wx.EXPAND, 0) 112 | self.HSlider[index].Add(self.Slider_v[index], 0, wx.ALL|wx.EXPAND, 5) 113 | self.vbox.Add(self.HSlider[index], 0, wx.ALL|wx.EXPAND, 5) 114 | 115 | def read_conf(self): 116 | self.data_conf = ConfigParser.SafeConfigParser() 117 | self.data_conf.read(self.home+'/.openplotter/SK-simulator.conf') 118 | if not self.data_conf.has_section('main'): 119 | value=[0,'navigation.courseOverGroundTrue',0,0,360,self.deg2rad,0] 120 | cfgfile = open(self.home+'/.openplotter/SK-simulator.conf','w') 121 | self.data_conf.add_section('main') 122 | self.data_conf.set('main','item_0', str(value)) 123 | self.data_conf.write(cfgfile) 124 | 125 | self.data_conf.read(self.home+'/.openplotter/SK-simulator.conf') 126 | 127 | self.Slider_list=[] 128 | for i in range(40): 129 | if self.data_conf.has_option('main','item_'+str(i)): 130 | data=self.data_conf.get('main','item_'+str(i)) 131 | try: 132 | temp_list=eval(data) 133 | except:temp_list=[] 134 | if temp_list!=[]: 135 | temp_list.append(0) 136 | self.Slider_list.append(temp_list) 137 | 138 | def allBtn(self,e): 139 | self.setCheckbox(True) 140 | 141 | def noneBtn(self,e): 142 | self.setCheckbox(False) 143 | 144 | def setCheckbox(self, value): 145 | for i in self.Slider_list: 146 | self.Slider[i[0]].SetValue(value) 147 | i[7]=value 148 | 149 | def on_change_checkbox(self,e): 150 | for i in self.Slider_list: 151 | i[7]=self.Slider[i[0]].GetValue() 152 | 153 | # thread 154 | def timer_act(self, event): 155 | SignalK = '{"updates": [{"$source":"OPsimulation","values":[ ' 156 | Erg='' 157 | for i in self.Slider_list: 158 | if i[7]: 159 | Erg += '{"path": "'+i[1]+'","value":'+str(self.Slider_v[i[0]].GetValue()*i[5]+i[6])+'},' 160 | if Erg!='': 161 | SignalK +=Erg[0:-1]+']}]}\n' 162 | self.sock.sendto(SignalK, ('127.0.0.1', 55557)) 163 | # end thread 164 | 165 | def OnClose(self, event): 166 | self.timer.Stop() 167 | self.Destroy() 168 | 169 | conf = Conf() 170 | home = conf.home 171 | 172 | if len(sys.argv)>1: 173 | if sys.argv[1]=='settings': 174 | subprocess.Popen(['leafpad', home+'/.openplotter/SK-simulator.conf']) 175 | else: 176 | app = wx.App() 177 | MyFrame().Show() 178 | app.MainLoop() -------------------------------------------------------------------------------- /tools/analog_ads1115.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import socket, time, datetime, subprocess, sys, os 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from ads1115 import Ads1115 23 | from conf_analog import Conf_analog 24 | 25 | conf_analog=Conf_analog() 26 | home = conf_analog.home 27 | 28 | if len(sys.argv)>1: 29 | if sys.argv[1]=='settings': 30 | print home+'/.openplotter/openplotter_analog.conf' 31 | subprocess.Popen(['leafpad',home+'/.openplotter/openplotter_analog.conf']) 32 | exit 33 | else: 34 | ads1115=Ads1115() 35 | 36 | a_index = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] 37 | a_value =[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0] 38 | a_index_max=15 39 | index=0 40 | active=['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'] 41 | SK_name=['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'] 42 | 43 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 44 | 45 | poll_interval = 1 46 | rate_analog = 1 47 | ADS1115='ADS1115_' 48 | 49 | for i in a_index: 50 | if (conf_analog.has_section(ADS1115+str(i))): 51 | active[i] = conf_analog.get(ADS1115+str(i), 'active')=='1' 52 | else: 53 | active[i] = False 54 | 55 | if active[i]: 56 | if 0==conf_analog.has_option(ADS1115+str(i), 'sk_name'): 57 | conf_analog.set(ADS1115+str(i), 'sk_name','0') 58 | 59 | SK_name[i] = conf_analog.get(ADS1115+str(i), 'sk_name') 60 | 61 | tick_analog=time.time() 62 | 63 | while True: 64 | tick2=time.time() 65 | time.sleep(poll_interval*1.0/1000.0) 66 | #GENERATE 67 | 68 | if tick2-tick_analog > rate_analog: 69 | tick_analog=time.time() 70 | 71 | list_signalk_path1=[] 72 | list_signalk1=[] 73 | 74 | for i in a_index: 75 | if active[i]: 76 | list_signalk_path1.append(SK_name[i]) 77 | list_signalk1.append(str(a_value[i])) 78 | 79 | if list_signalk1: 80 | SignalK = '{"updates": [{"$source": "OPsensors.I2C.ADS1115","values":[ ' 81 | Erg='' 82 | for i in range(0,len(list_signalk1)): 83 | Erg += '{"path": "'+list_signalk_path1[i]+'","value":'+list_signalk1[i]+'},' 84 | SignalK +=Erg[0:-1]+']}]}\n' 85 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 86 | else: 87 | index+=1 88 | if index>a_index_max: index=0 89 | if active[index]: 90 | a_value[index]=ads1115.read(index) 91 | -------------------------------------------------------------------------------- /tools/analog_ina219.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | 18 | import socket, time, math, csv, datetime, subprocess, sys, os 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from ads1115 import Ads1115 23 | from conf_analog import Conf_analog 24 | from ina219 import INA219 25 | from ina219 import DeviceRangeError 26 | 27 | SHUNT_OHMS = 0.1 28 | 29 | conf_analog=Conf_analog() 30 | home = conf_analog.home 31 | 32 | if len(sys.argv)>1: 33 | if sys.argv[1]=='settings': 34 | print home+'/.openplotter/openplotter_analog.conf' 35 | subprocess.Popen(['leafpad',home+'/.openplotter/openplotter_analog.conf']) 36 | exit 37 | else: 38 | 39 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 40 | 41 | poll_interval = 1 42 | rate_analog = 1 43 | 44 | tick_analog=time.time() 45 | ina = INA219(SHUNT_OHMS,1.0,0x41) 46 | ina.configure() 47 | 48 | try: 49 | inaV = ina.voltage() 50 | inaA = ina.current()/1000 51 | inaW = inaV*inaA 52 | except DeviceRangeError as e: 53 | print e 54 | 55 | while True: 56 | tick2=time.time() 57 | time.sleep(poll_interval*1.0/1000.0) 58 | #GENERATE 59 | 60 | if tick2-tick_analog > rate_analog: 61 | tick_analog=time.time() 62 | 63 | list_signalk_path1=[] 64 | list_signalk1=[] 65 | 66 | try: 67 | inaV = inaV*0.8 +ina.voltage()*0.2 68 | inaA = inaA*0.8 +ina.current()/1000*0.2 69 | inaW = inaV*inaA 70 | except DeviceRangeError as e: 71 | print e 72 | 73 | SignalK = '{"updates": [{"$source": "OPsensors.I2C.ina219","values":[ ' 74 | Erg='' 75 | Erg += '{"path": "electrical.batteries.rpi.current","value":'+str(inaA)+'},' 76 | Erg += '{"path": "electrical.batteries.rpi.voltage","value":'+str(inaV)+'},' 77 | Erg += '{"path": "electrical.batteries.rpi.power","value":'+str(inaW)+'},' 78 | SignalK +=Erg[0:-1]+']}]}\n' 79 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 80 | -------------------------------------------------------------------------------- /tools/example_tool_arduino2SK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ''' 3 | //Arduino code 4 | int i=0; 5 | // the setup routine runs once when you press reset: 6 | void setup() { 7 | Serial.begin(9600); 8 | } 9 | 10 | void loop() { 11 | if (i>100) i=0; 12 | i++; 13 | Serial.print("ArduinoValue:"); 14 | Serial.println(i); 15 | delay(300); // delay in between reads for stability 16 | } 17 | ''' 18 | 19 | import signal, sys, time, socket, datetime, subprocess, math, serial 20 | 21 | # Control-C signal handler to suppress exceptions if user presses Control C 22 | # This is totally optional. 23 | def signal_handler(sig, frame): 24 | print('You pressed Ctrl+C!!!!') 25 | sys.exit(0) 26 | 27 | # init 28 | signal.signal(signal.SIGINT, signal_handler) 29 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 30 | ser = serial.Serial('/dev/ttyOP_LEONARDO', 9600, timeout=1) 31 | ser.flush() 32 | 33 | Value = 0 34 | # forever loop until user presses Control-C 35 | while 1: 36 | serLine = ser.readline() 37 | if 'ArduinoValue:' in serLine: 38 | Value = serLine[13:-1] 39 | #print Value 40 | 41 | SignalK = '{"updates": [{"$source":"OPserial.BAT.V1","values":[{"path": "electrical.batteries.main.voltage","value":'+str(Value)+'}]}]}\n' 42 | #print SignalK 43 | sock.sendto(SignalK, ('localhost', 55559)) 44 | time.sleep(0.300) 45 | 46 | -------------------------------------------------------------------------------- /tools/example_tool_short_time2SK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import signal, sys, time, socket, datetime,subprocess,math 3 | 4 | # Control-C signal handler to suppress exceptions if user presses Control C 5 | # This is totally optional. 6 | def signal_handler(sig, frame): 7 | print('You pressed Ctrl+C!!!!') 8 | if board is not None: 9 | board.reset() 10 | sys.exit(0) 11 | 12 | # init 13 | signal.signal(signal.SIGINT, signal_handler) 14 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 15 | 16 | # forever loop until user presses Control-C 17 | while 1: 18 | tt = time.time() 19 | Value = tt - math.trunc(tt / 60) * 60 20 | 21 | SignalK = '{"updates": [{"$source":"OPserial.BAT.ABC","values":[{"path": "electrical.batteries.main.voltage","value":'+str(Value)+'}]}]}\n' 22 | #print SignalK 23 | sock.sendto(SignalK, ('localhost', 55559)) 24 | time.sleep(1.000) 25 | 26 | -------------------------------------------------------------------------------- /tools/install analog.txt: -------------------------------------------------------------------------------- 1 | Analog sensors 2 | I have a ADS1115 16 bit adc for i2c 3 | and different types of arduino/teensy/stm32 4 | 5 | First ADS1115 6 | It can be connected to the i2c bus in the same way you connect for example a pressure sensor. 7 | You can connect up to 4 ADS1115 8 | 9 | The config file (openplotter_analog.conf) is located in the tools folder. 10 | There are 16 sections ([ADS1115_0],[ADS1115_1],[ADS1115_2],[ADS1115_3],[ADS1115_4],[ADS1115_5]) 11 | 12 | [ADS1115_0] active = 1 13 | gain = 0 14 | samples = 6 15 | ohmmeter = 0 16 | fixed_resistor = 0 17 | high_voltage = 3000 18 | voltage_divider = 0 19 | upper_resistance = 1000 20 | lower_resistance = 1000 21 | adjust = 0 22 | sk_name = tanks.fuel.left.currentLevel 23 | adjust_points = [[100.0,0.0],[5000.0,90.0],[9000.0,100.0]] 24 | 25 | If a channel is used active must be set to 1 26 | The gain setting can be changed with gain. 27 | gain = 0 +/- 6.144V 28 | gain = 1 +/- 4.096V 29 | gain = 2 +/- 2.048V 30 | gain = 3 +/- 1.024V 31 | gain = 4 +/- 0.512V 32 | gain = 5 +/- 0.256V 33 | samples setting can be changed with samples (see table). 34 | samples 0 8 samples per second 35 | samples 1 16 samples per second 36 | samples 2 32 samples per second 37 | samples 3 64 samples per second 38 | samples 4 128 samples per second 39 | samples 5 250 samples per second 40 | samples 6 475 samples per second 41 | samples 7 860 samples per second 42 | ohmmeter can be set to 1 to measure the resistance of a sensor. 43 | fixed_resistor must be set to the resistance of the fixed resistor and 44 | high_voltage is the voltage you put on the two resistors in serial. 45 | The resistance you want to measure is connected on one side to ground and 46 | on the other side to the fixed resistor and analog input of the adc. 47 | The other side of the fixed resistor is connected to + pol (for example 3.3V (high_voltage)) 48 | voltage_divider can be set to 1 if you want to have Volt values. 49 | If you want to measure 12 V with a adc witch is only capable of max 3.3V, 50 | you need a voltage divider in form of two resistors. (50k+10k would put the voltage from 12V to 2V) 51 | upper_resistance has to be set to 50000 and lower resistance to 10000 for this example. 52 | Look at the picture on http://forum.arduino.cc/index.php?topic=214930.0 53 | adjust is only for adjusting the offset 54 | The value is send to SignalK on the name you set in sk_name. 55 | adjust_points 56 | You can put in some points of a curve. 57 | Between this point the value is calculated linear. 58 | This is the easiest way to get good results. 59 | It can be used in combination with voltage_devider or ohmmeter. 60 | 61 | Some settings are described under Arduino 62 | 63 | Second Arduino 64 | 65 | Arduinos have a 10 bit adc 66 | teensy have 10 to 16 bit adc 67 | stm32 have 12 to 16 bit adc 68 | 69 | For Arduino you must have: 70 | Arduino ide compatible board with usb 71 | Arduino ide 72 | Install Pymata: 73 | sudo apt-get install python-pip 74 | sudo pip install pymata 75 | 76 | For ads1115 you must have: 77 | Install smbus: 78 | sudo apt-get install python-smbus 79 | 80 | First you upload FirmataStandard from Arduino ide to your board (for help use google) 81 | Connect the board to your rpi. 82 | Use USB manager to give the board the name ttyOP_FIRM 83 | 84 | Now edit openplotter.conf at the section [TOOLS] 85 | put in 86 | [TOOLS] 87 | py = [['Analog ads1115','put analog values to SignalK','analog_ads1115.py','0'],['Analog MCP3008','put analog values to SignalK','analog_MCP3008.py','0'],['Analog Firmata','put analog values to SignalK','oppymata.py','0']] 88 | (change 0 to 1 for autostart) 89 | 90 | The config file section for Firmata is easy in comparison with the ads1115. 91 | 92 | There are up to 16 sections ([FIRMATA_0]..[FIRMATA_15]) 93 | 94 | [FIRMATA_1] 95 | sk_name = tanks.fuel.right.currentLevel 96 | adjust_points = [[52.0,0.0],[522.0,25.0],[708.0,50.0],[913.0,100],[1024.0,100.01]] 97 | -------------------------------------------------------------------------------- /tools/op_pymata_check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import signal, sys, time 18 | from PyMata.pymata import PyMata 19 | 20 | def signal_handler(sig, frame): 21 | print('You pressed Ctrl+C!!!!') 22 | board.close() 23 | if board is not None: 24 | board.reset() 25 | sys.exit(0) 26 | 27 | signal.signal(signal.SIGINT, signal_handler) 28 | board = PyMata("/dev/ttyOP_FIRM") 29 | time.sleep(1) 30 | board.reset 31 | board.close 32 | -------------------------------------------------------------------------------- /tools/openplotter_analog.conf: -------------------------------------------------------------------------------- 1 | [ADS1115_0] 2 | active = 1 3 | gain = 0 4 | samples = 6 5 | ohmmeter = 0 6 | fixed_resistor = 0 7 | high_voltage = 3000 8 | voltage_divider = 0 9 | upper_resistance = 1000 10 | lower_resistance = 1000 11 | adjust = 0 12 | sk_name = tanks.fuel.left.currentLevel 13 | 14 | [ADS1115_1] 15 | active = 1 16 | gain = 4 17 | samples = 6 18 | ohmmeter = 0 19 | fixed_resistor = 1000 20 | high_voltage = 6263 21 | voltage_divider = 0 22 | upper_resistance = 22000 23 | lower_resistance = 2200 24 | adjust = 0 25 | sk_name = tanks.fuel.right.currentLevel 26 | 27 | [ADS1115_2] 28 | active = 1 29 | gain = 2 30 | samples = 6 31 | ohmmeter = 1 32 | fixed_resistor = 17800 33 | high_voltage = 3300 34 | voltage_divider = 0 35 | upper_resistance = 22000 36 | lower_resistance = 2200 37 | adjust = 0 38 | sk_name = propulsion.port.waterTemperature 39 | 40 | [ADS1115_3] 41 | active = 1 42 | gain = 2 43 | samples = 6 44 | ohmmeter = 1 45 | fixed_resistor = 17800 46 | high_voltage = 3300 47 | voltage_divider = 0 48 | upper_resistance = 22000 49 | lower_resistance = 2200 50 | adjust = 0 51 | adjust_points = [[100.0,0.0],[5000.0,90.0],[9000.0,100.0]] 52 | sk_name = propulsion.starboard.waterTemperature 53 | 54 | [FIRMATA_1] 55 | sk_name = tanks.fuel.right.currentLevel 56 | adjust_points = [[0,0.0],[1024.0,100.0]] 57 | 58 | [FIRMATA_2] 59 | sk_name = tanks.fuel.left.currentLevel 60 | adjust_points = [[0,0.0],[17000,100.0]] -------------------------------------------------------------------------------- /tools/oppymata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import signal, sys, time, socket, datetime, subprocess, os 18 | from PyMata.pymata import PyMata 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from conf import Conf 23 | from language import Language 24 | from conf_analog import Conf_analog 25 | 26 | # Control-C signal handler to suppress exceptions if user presses Control C 27 | # This is totally optional. 28 | def signal_handler(sig, frame): 29 | print('You pressed Ctrl+C!!!!') 30 | if board is not None: 31 | board.reset() 32 | sys.exit(0) 33 | 34 | def interpolread(idx,erg): 35 | if adjust_point_active[idx]: 36 | lin = -999999 37 | for index,item in enumerate(adjust_point[idx]): 38 | if index==0: 39 | if erg <= item[0]: 40 | lin = item[1] 41 | #print 'under range' 42 | return lin 43 | save = item 44 | else: 45 | if erg <= item[0]: 46 | a = (item[1]-save[1])/(item[0]-save[0]) 47 | b = item[1]-a*item[0] 48 | lin = a*erg +b 49 | return lin 50 | save = item 51 | 52 | if lin == -999999: 53 | #print 'over range' 54 | lin = save[1] 55 | return lin 56 | else: 57 | return erg 58 | 59 | def init(): 60 | signal.signal(signal.SIGINT, signal_handler) 61 | 62 | conf_analog = Conf_analog() 63 | 64 | FIRMATA='FIRMATA_' 65 | 66 | #example to set arduino A2 as analog input -> config file "openplotter_analog.conf" 67 | #[FIRMATA_2] 68 | #sk_name = tanks.fuel.left.currentLevel 69 | #adjust_points = [[403.0,0.0],[522.0,25.0],[708.0,50.0],[913.0,100],[1024.0,100.01]] 70 | 71 | index=0 72 | for i in range(16): 73 | if conf_analog.has_section(FIRMATA+str(i)): 74 | channel.append(i) 75 | RawValue.append(0) 76 | adjust_point_active.append(0) 77 | adjust_point.append(0) 78 | channel_index.append(index) 79 | board.set_pin_mode(i, board.INPUT, board.ANALOG) 80 | if 0==conf_analog.has_option(FIRMATA+str(i), 'sk_name'): 81 | conf_analog.set(FIRMATA+str(i), 'sk_name','0') 82 | 83 | SK_name.append(conf_analog.get(FIRMATA+str(i), 'sk_name')) 84 | 85 | if 0==conf_analog.has_option(FIRMATA+str(i), 'adjust_points'): 86 | adjust_point_active[index] = 0 87 | else: 88 | line = conf_analog.get(FIRMATA+str(i), 'adjust_points') 89 | if line: 90 | adjust_point[index]=eval(line) 91 | adjust_point_active[index] = 1 92 | else: adjust_point[index]=[] 93 | index+=1 94 | 95 | conf = Conf() 96 | home = conf.home 97 | currentpath = home+conf.get('GENERAL', 'op_folder')+'/openplotter' 98 | 99 | if len(sys.argv)>1: 100 | index=1 101 | if sys.argv[1]=='settings': 102 | print home+'/.openplotter/openplotter_analog.conf' 103 | subprocess.Popen(['leafpad',home+'/.openplotter/openplotter_analog.conf']) 104 | exit 105 | else: 106 | RawValue=[] 107 | adjust_point=[] 108 | adjust_point_active=[] 109 | channel=[] 110 | channel_index=[] 111 | SK_name=[] 112 | index=0 113 | SignalK='' 114 | 115 | if os.path.exists('/dev/ttyOP_FIRM') and index == 0: 116 | output = subprocess.check_output(['python', currentpath+'/tools/op_pymata_check.py']) 117 | if 'Total Number' in output: 118 | pass 119 | else: 120 | print 'some errors so second try' 121 | output = subprocess.check_output(['python', currentpath+'/tools/op_pymata_check.py']) 122 | if 'Total Number' in output: 123 | pass 124 | else: 125 | print 'No Firmata on /dev/ttyOP_FIRM' 126 | sys.exit(0) 127 | 128 | board = PyMata("/dev/ttyOP_FIRM") 129 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 130 | 131 | init() 132 | index=0 133 | length=len(channel_index)-1 134 | 135 | # A forever loop until user presses Control-C 136 | while 1: 137 | RawValue[index]=board.analog_read(channel[index]) 138 | time.sleep(0.100) 139 | 140 | index+=1 141 | if index > length: 142 | index=0 143 | 144 | SignalK = '{"updates": [{"$source":"OPserial.ARD.ANA","values":[ ' 145 | Erg='' 146 | for i in channel_index: 147 | Erg += '{"path": "'+SK_name[i]+'","value":'+str(interpolread(i,RawValue[i]))+'},' 148 | 149 | SignalK +=Erg[0:-1]+']}]}\n' 150 | #print SignalK 151 | sock.sendto(SignalK, ('127.0.0.1', 55559)) 152 | time.sleep(0.100) 153 | else: 154 | print 'No serialport ttyOP_FIRM (Arduino with Firmata) found.' 155 | print 'Have you add the Arduino port in USB manager?' 156 | -------------------------------------------------------------------------------- /tools/rtl_433SK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # This file is part of Openplotter. 4 | # Copyright (C) 2015 by sailoog 5 | # e-sailing 6 | # Openplotter is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 2 of the License, or 9 | # any later version. 10 | # Openplotter is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Openplotter. If not, see . 17 | import signal, sys, os, time, socket, subprocess 18 | import shlex 19 | 20 | op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') 21 | sys.path.append(op_folder+'/classes') 22 | from conf_analog import Conf_analog 23 | 24 | sen_frequenz = '433967780' 25 | sen_type = '03' 26 | #for sensor type see: rtl_433 -h 27 | sen_temp_SK = 'environment.inside.refrigerator.temperature' 28 | sen_humi_SK = 'environment.inside.humidity' 29 | 30 | # Control-C signal handler to suppress exceptions if user presses Control C 31 | # This is totally optional. 32 | def signal_handler(sig, frame): 33 | print('You pressed Ctrl+C!!!!') 34 | if board is not None: 35 | board.reset() 36 | sys.exit(0) 37 | 38 | def interpolread(idx,erg): 39 | if adjust_point_active[idx]: 40 | lin = -999999 41 | for index,item in enumerate(adjust_point[idx]): 42 | if index==0: 43 | if erg <= item[0]: 44 | lin = item[1] 45 | #print 'under range' 46 | return lin 47 | save = item 48 | else: 49 | if erg <= item[0]: 50 | a = (item[1]-save[1])/(item[0]-save[0]) 51 | b = item[1]-a*item[0] 52 | lin = a*erg +b 53 | return lin 54 | save = item 55 | 56 | if lin == -999999: 57 | #print 'over range' 58 | lin = save[1] 59 | return lin 60 | else: 61 | return erg 62 | 63 | def init(): 64 | signal.signal(signal.SIGINT, signal_handler) 65 | 66 | conf_analog = Conf_analog() 67 | 68 | SK_name.append(sen_temp_SK); 69 | SK_name.append(sen_humi_SK); 70 | 71 | if len(sys.argv)>1: 72 | if sys.argv[1]=='settings': 73 | print 'No config file or gui! Changes must be made in the python file' 74 | exit 75 | else: 76 | index=0 77 | SignalK='' 78 | RawValue=[] 79 | SK_name=[] 80 | channel_rtl='' 81 | type_rtl='' 82 | output='' 83 | finish=False 84 | proc = subprocess.Popen(shlex.split('rtl_433 -f'+ sen_frequenz + ' -R' + sen_type +' -s280000'), bufsize = 1, stdout=subprocess.PIPE) 85 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 86 | init() 87 | index=0 88 | 89 | for line in iter(proc.stdout.readline, b''): 90 | if 'Temperature:' in line: 91 | temperature_rtl = float(line[14:-3]) 92 | if line[-2:-1] == 'F': 93 | temperature_rtl = (temperature_rtl-32.)/1.8 +273.15 94 | else: 95 | temperature_rtl += 273.15 96 | output += line[:-1] + ' float=' + str(temperature_rtl) + '\n' 97 | elif 'Humidity:' in line: 98 | humidity_rtl = float(line[11:-3]) 99 | output += line[:-1] + ' float=' + str(humidity_rtl) + '\n' 100 | finish=True 101 | elif 'Channel:' in line: 102 | channel_rtl = line[-2:-1] 103 | output += line[:-1] + ' char=' + channel_rtl + '\n' 104 | elif 'Prologue sensor' in line: 105 | type_rtl = 'PRO' 106 | #output += ' shortcut=' 107 | output += str(line[:-1]) + ' shortcut=' + str(type_rtl) + '\n' 108 | else: 109 | output += line 110 | if finish: 111 | finish=False 112 | print output 113 | output='' 114 | SignalK = '{"updates":[{"$source":"OPsensors.RTL433.'+type_rtl+channel_rtl+'","values":[ ' 115 | Erg='' 116 | Erg += '{"path": "'+SK_name[1]+'","value":'+str(humidity_rtl)+'},' 117 | Erg += '{"path": "'+SK_name[0]+'","value":'+str(temperature_rtl)+'},' 118 | 119 | SignalK +=Erg[0:-1]+']}]}\n' 120 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 121 | print SignalK 122 | sys.stdout.flush() 123 | time.sleep(0.2) 124 | 125 | proc.wait() 126 | -------------------------------------------------------------------------------- /update/default_openplotter_desk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 3 | echo "APPLYING DEFAULT SETTINGS..." 4 | echo 5 | cd ~/.config/pcmanfm/LXDE-pi 6 | echo "[*]" > desktop-items-0.conf 7 | echo "wallpaper_mode=center" >> desktop-items-0.conf 8 | echo "wallpaper_common=1" >> desktop-items-0.conf 9 | echo "wallpaper=/usr/share/raspberrypi-artwork/openplotter_RPI_desktop.png" >> desktop-items-0.conf 10 | echo "desktop_bg=#d6d6d3d3dede" >> desktop-items-0.conf 11 | echo "desktop_fg=#000000000000" >> desktop-items-0.conf 12 | echo "desktop_shadow=#d6d6d3d3dede" >> desktop-items-0.conf 13 | echo "desktop_font=Roboto Light 12" >> desktop-items-0.conf 14 | echo "show_wm_menu=0" >> desktop-items-0.conf 15 | echo "sort=mtime;ascending;" >> desktop-items-0.conf 16 | echo "show_documents=0" >> desktop-items-0.conf 17 | echo "show_trash=0" >> desktop-items-0.conf 18 | echo "show_mounts=0" >> desktop-items-0.conf 19 | echo "prefs_app=pipanel" >> desktop-items-0.conf 20 | echo -e '[Desktop Entry]\nName=OpenPlotter debugging\nExec=lxterminal -e openplotter\nIcon=/home/pi/.config/openplotter/openplotter_debug.ico\nStartupNotify=true\nCategories=OpenPlotter\nTerminal=false\nType=Application\nVersion=1.0' > /home/pi/.local/share/applications/openplotter_debug.desktop 21 | echo 22 | echo "DELETING UNUSED ICONS..." 23 | echo 24 | sudo bash -c 'echo -e "[Desktop Entry]\nName=OpenCPN\nComment=Open source chart plotter / navigator\nExec=opencpn\nIcon=opencpn\nStartupNotify=true\nCategories=OpenPlotter\nTerminal=false\nType=Application\nVersion=1.0" > /usr/share/applications/opencpn.desktop' 25 | sudo rm -rf /usr/share/raspi-ui-overrides/applications/magpi.desktop 26 | sudo rm -rf /usr/share/raspi-ui-overrides/applications/raspi_resources.desktop 27 | sudo rm -rf /usr/share/raspi-ui-overrides/applications/help.desktop 28 | echo 29 | echo "DISABLING SCREENSAVER..." 30 | echo 31 | sudo bash -c 'echo -e "\n@xset s 0 0\n@xset s noblank\n@xset s noexpose\n@xset dpms 0 0 0\n" >> /home/pi/.config/lxsession/LXDE-pi/autostart' 32 | read -p "FINISHED, PRESS ENTER TO REBOOT SYSTEM." 33 | shutdown -r now -------------------------------------------------------------------------------- /update/update_OpenCPN.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 3 | echo "CLOSING OPENCPN..." 4 | echo 5 | pkill -9 opencpn 6 | echo 7 | echo "UPDATING PACKAGE LISTS..." 8 | echo 9 | sudo apt-get -qq update 10 | if [ $? -ne 0 ]; then 11 | echo 12 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 13 | exit 1 14 | fi 15 | echo 16 | echo "UPDATING OPENCPN..." 17 | echo 18 | sudo apt-get -qq install opencpn 19 | if [ $? -ne 0 ]; then 20 | echo 21 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 22 | exit 1 23 | fi 24 | echo 25 | echo "EDITING OPENCPN MENU..." 26 | echo 27 | sudo bash -c 'echo -e "[Desktop Entry]\nName=OpenCPN\nComment=Open source chart plotter / navigator\nExec=opencpn\nIcon=opencpn\nStartupNotify=true\nCategories=OpenPlotter\nTerminal=false\nType=Application\nVersion=1.0" > /usr/share/applications/opencpn.desktop' 28 | echo 29 | read -p "FINISHED PRESS ENTER TO EXIT" 30 | -------------------------------------------------------------------------------- /update/update_OpenCPN_plugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 3 | echo "UPDATING PACKAGE LISTS..." 4 | echo 5 | sudo apt-get -qq update 6 | if [ $? -ne 0 ]; then 7 | echo 8 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 9 | exit 1 10 | fi 11 | echo 12 | echo "UPDATING OPENCPN PLUGINS..." 13 | echo 14 | sudo apt-get -qq install oesenc-pi opencpn-plugin-aisradar opencpn-plugin-br24radar opencpn-plugin-calculator opencpn-plugin-climatology opencpn-plugin-climatology-data opencpn-plugin-celestial opencpn-plugin-dr opencpn-plugin-draw opencpn-plugin-gradar opencpn-plugin-gxradar opencpn-plugin-iacfleet opencpn-plugin-launcher opencpn-plugin-logbookkonni opencpn-plugin-objsearch opencpn-plugin-ocpndebugger opencpn-plugin-otcurrent opencpn-plugin-polar opencpn-plugin-projections opencpn-plugin-rotationctrl opencpn-plugin-route opencpn-plugin-rtlsdr opencpn-plugin-s63 opencpn-plugin-sar opencpn-plugin-squiddio opencpn-plugin-statusbar opencpn-plugin-sweepplot opencpn-plugin-vdr opencpn-plugin-watchdog opencpn-plugin-weatherfax opencpn-plugin-weatherrouting 15 | if [ $? -ne 0 ]; then 16 | echo 17 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 18 | exit 1 19 | fi 20 | echo 21 | read -p "FINISHED PRESS ENTER TO EXIT" 22 | -------------------------------------------------------------------------------- /update/update_OpenPlotter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | major=$1 3 | version=$2 4 | status=$3 5 | repository=$4 6 | op_folder=$(crudini --get ~/.openplotter/openplotter.conf GENERAL op_folder) 7 | if [ -z $major ]; then 8 | major=1 9 | fi 10 | if [ -z $status ]; then 11 | status="beta" 12 | fi 13 | if [ -z $repository ]; then 14 | repository="openplotter" 15 | fi 16 | if [ -z $op_folder ]; then 17 | op_folder="/.config" 18 | fi 19 | 20 | cd $HOME$op_folder 21 | 22 | echo 23 | echo "DOWNLOADING NEW OPENPLOTTER CODE..." 24 | echo 25 | rm -rf openplotter_tmp 26 | if [ $status = "stable" ]; then 27 | git clone https://github.com/$repository/openplotter.git openplotter_tmp 28 | else 29 | git clone -b beta https://github.com/$repository/openplotter.git openplotter_tmp 30 | fi 31 | if [ $? -ne 0 ]; then 32 | echo 33 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 34 | exit 1 35 | fi 36 | echo 37 | echo "CREATING OPENPLOTTER CODE BACKUP..." 38 | echo 39 | DIRDATE=`date +openplotter_bak_%Y_%m_%d:%H:%M:%S` 40 | cp -a openplotter/ $DIRDATE/ 41 | cd $DIRDATE 42 | find . -name "*.pyc" -type f -delete 43 | 44 | cd $HOME$op_folder 45 | 46 | source openplotter_tmp/update/update_settings.sh 47 | if [ $major = 1 ]; then 48 | source openplotter_tmp/update/update_dependencies.sh 49 | fi 50 | echo 51 | echo "COMPRESSING OPENPLOTTER CODE BACKUP INTO HOME..." 52 | echo 53 | tar cjf ~/$DIRDATE.tar.bz2 $DIRDATE 54 | echo 55 | echo "DELETING OLD OPENPLOTTER CODE FILES..." 56 | echo 57 | rm -rf openplotter 58 | rm -rf $DIRDATE 59 | mv openplotter_tmp openplotter 60 | echo 61 | read -p "FINISHED, PRESS ENTER TO REBOOT SYSTEM." 62 | shutdown -r now 63 | 64 | -------------------------------------------------------------------------------- /update/update_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | status=$3 3 | op_folder=$(crudini --get ~/.openplotter/openplotter.conf GENERAL op_folder) 4 | 5 | if [ -z $status ]; then 6 | status="stable" 7 | fi 8 | 9 | if [ -z $op_folder ]; then 10 | op_folder="/.config" 11 | fi 12 | 13 | if [ $status = "stable" ]; then 14 | repository="openplotter" 15 | else 16 | repository="sailoog" 17 | fi 18 | 19 | cd $HOME$op_folder 20 | 21 | echo 22 | echo "REMOVING UNUSED PACKAGES..." 23 | echo 24 | sudo apt-get -y remove --purge librtimulib-dev librtimulib-utils librtimulib7 python-rtimulib python3-rtimulib realvnc* xrdp 25 | sudo apt-get -y autoremove 26 | echo 27 | echo "UPDATING PACKAGE LISTS..." 28 | echo 29 | sudo apt-get update 30 | if [ $? -ne 0 ]; then 31 | echo 32 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 33 | exit 1 34 | fi 35 | echo 36 | echo "UPDATING PACKAGES..." 37 | echo 38 | sudo apt-get -y upgrade 39 | if [ $? -ne 0 ]; then 40 | echo 41 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 42 | exit 1 43 | fi 44 | echo 45 | echo "UPGRADING RASPBIAN..." 46 | echo 47 | sudo apt-get -y dist-upgrade 48 | if [ $? -ne 0 ]; then 49 | echo 50 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 51 | exit 1 52 | fi 53 | echo 54 | echo "INSTALLING DEPENDENCIES..." 55 | echo 56 | sudo apt-get -y install gettext gpsd python-w1thermsensor x11vnc xrdp python-wxgtk3.0 hostapd dnsmasq isc-dhcp-server network-manager network-manager-gnome mpg123 python-gammu gammu mosquitto libusb-1.0-0-dev libfftw3-dev qt5-qmake libasound2-dev libpulse-dev autoconf automake python-dev python-matplotlib bridge-utils crudini libqt5gui5 libqt5core5a libqt5network5 libqt5widgets5 libqt5svg5 libportaudio2 make gcc xsltproc curl git build-essential libtool libusb-1.0.0-dev librtlsdr-dev rtl-sdr i2c-tools cmake libqt4-dev libproj-dev libnova-dev swig python-numpy python-scipy python-serial python-gps python-PIL python-opengl python-pillow python-flask libnss-mdns avahi-utils libavahi-compat-libdnssd-dev 57 | if [ $? -ne 0 ]; then 58 | echo 59 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 60 | exit 1 61 | fi 62 | echo 63 | echo "INSTALLING PYTHON PACKAGES..." 64 | echo 65 | sudo easy_install pip 66 | sudo pip install --upgrade paho-mqtt pyudev pyrtlsdr pynmea2 twython websocket-client spidev PyMata requests_oauthlib requests pyglet pywavefront ujson 67 | if [ $? -ne 0 ]; then 68 | echo 69 | read -p "#### ERROR. ABORTING, PRESS ENTER TO EXIT ####" 70 | exit 1 71 | fi 72 | echo 73 | echo "UPDATING NODEJS AND NODE-RED..." 74 | echo 75 | rm -rf $HOME/.node-red/node_modules/node-red-contrib-freeboard 76 | update-nodejs-and-nodered 77 | sudo rm -rf /usr/share/applications/Node-RED.desktop 78 | echo 79 | echo "UPDATING SIGNAL K..." 80 | echo 81 | cd $HOME$op_folder 82 | rm -rf signalk-server-node_tmp 83 | git clone https://github.com/$repository/signalk-server-node.git signalk-server-node_tmp 84 | cd ~/.config/signalk-server-node_tmp 85 | npm install 86 | npm install mdns 87 | cd $HOME$op_folder 88 | rm -rf signalk-server-node 89 | mv signalk-server-node_tmp signalk-server-node 90 | echo 91 | echo "COMPILING PACKAGES..." 92 | echo 93 | cd $HOME$op_folder 94 | mkdir compiling 95 | 96 | cd $HOME$op_folder/compiling 97 | git clone https://github.com/$repository/kalibrate-rtl.git 98 | cd kalibrate-rtl 99 | ./bootstrap && CXXFLAGS='-W -Wall -O3' 100 | ./configure 101 | make 102 | sudo make install 103 | 104 | cd $HOME$op_folder/compiling 105 | git clone https://github.com/$repository/rtl_433.git 106 | cd rtl_433/ 107 | mkdir build 108 | cd build 109 | cmake ../ 110 | make 111 | sudo make install 112 | 113 | cd $HOME$op_folder/compiling 114 | pkill aisdecoder 115 | git clone https://github.com/$repository/aisdecoder.git 116 | cd aisdecoder 117 | cmake -DCMAKE_BUILD_TYPE=release 118 | make 119 | sudo cp aisdecoder /usr/local/bin 120 | 121 | cd $HOME$op_folder/compiling 122 | git clone https://github.com/$repository/kplex.git 123 | cd kplex 124 | make 125 | sudo make install 126 | 127 | cd $HOME$op_folder/compiling 128 | git clone git://github.com/$repository/canboat 129 | cd canboat 130 | make 131 | sudo make install 132 | 133 | cd $HOME$op_folder/compiling 134 | git clone https://github.com/$repository/geomag.git 135 | cd geomag/geomag 136 | python setup.py build 137 | sudo python setup.py install 138 | 139 | cd $HOME$op_folder/compiling 140 | git clone https://github.com/$repository/RTIMULib2.git 141 | cd RTIMULib2/Linux 142 | mkdir build 143 | cd build 144 | cmake .. 145 | make -j4 146 | sudo make install 147 | sudo ldconfig 148 | cd .. 149 | cd RTIMULibDrive 150 | make -j4 151 | sudo make install 152 | cd .. 153 | cd RTIMULibDrive10 154 | make -j4 155 | sudo make install 156 | cd .. 157 | cd python 158 | python setup.py build 159 | sudo python setup.py install 160 | 161 | cd $HOME$op_folder/compiling 162 | git clone https://github.com/$repository/pypilot 163 | cd pypilot 164 | python setup.py build 165 | sudo python setup.py install 166 | 167 | cd $HOME$op_folder/compiling 168 | git clone https://github.com/$repository/pypilot_data.git 169 | if [ ! -d ~/.pypilot ]; then 170 | mkdir ~/.pypilot 171 | fi 172 | cd pypilot_data 173 | cp -f ui/Vagabond.mtl ~/.pypilot/ 174 | cp -f ui/Vagabond.obj ~/.pypilot/ 175 | cp -f ui/compass.png ~/.pypilot/ 176 | 177 | cd $HOME$op_folder 178 | sudo rm -rf $HOME$op_folder/compiling/ 179 | 180 | echo '{"host": "localhost"}' > ~/.pypilot/signalk.conf 181 | 182 | if grep -Fq "self.shininess = min(128, self.shininess)" /usr/local/lib/python2.7/dist-packages/pywavefront/material.py 183 | then 184 | true 185 | else 186 | sudo sed -i '103 i \\tself.shininess = min(128, self.shininess)' /usr/local/lib/python2.7/dist-packages/pywavefront/material.py 187 | fi 188 | 189 | echo 190 | echo "INSTALLING/UPDATING GQRX..." 191 | echo 192 | cd ~/.config 193 | wget https://github.com/csete/gqrx/releases/download/v2.6/gqrx-2.6-rpi3-3.tar.xz 194 | tar xf gqrx-2.6-rpi3-3.tar.xz 195 | rm gqrx-2.6-rpi3-3.tar.xz 196 | rm -rf gqrx 197 | mv gqrx-2.6-rpi3-3 gqrx 198 | cd gqrx 199 | ./setup_gqrx.sh 200 | 201 | cd $HOME$op_folder 202 | -------------------------------------------------------------------------------- /update/update_settings.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | op_folder=$(crudini --get ~/.openplotter/openplotter.conf GENERAL op_folder) 3 | if [ -z $op_folder ]; then 4 | op_folder="/.config" 5 | fi 6 | 7 | cd $HOME$op_folder 8 | 9 | echo 10 | echo "APPLYING SETTINGS..." 11 | echo 12 | 13 | chmod 755 openplotter_tmp/openplotter 14 | chmod 755 openplotter_tmp/keyword 15 | chmod 755 openplotter_tmp/startup 16 | 17 | if [ ! -d ~/.openplotter ]; then 18 | mkdir ~/.openplotter 19 | fi 20 | 21 | if [ ! -d ~/.openplotter/tools ]; then 22 | mkdir ~/.openplotter/tools 23 | fi 24 | 25 | cp -f openplotter_tmp/tools/demo_tool.py ~/.openplotter/tools/ 26 | 27 | if [ ! -f ~/.openplotter/openplotter.conf ]; then 28 | cp -f $DIRDATE/openplotter.conf ~/.openplotter/ 29 | fi 30 | newversion=$(crudini --get openplotter_tmp/openplotter.conf GENERAL version) 31 | newstate=$(crudini --get openplotter_tmp/openplotter.conf GENERAL state) 32 | crudini --set ~/.openplotter/openplotter.conf GENERAL version $newversion 33 | crudini --set ~/.openplotter/openplotter.conf GENERAL state $newstate 34 | 35 | if [ ! -f ~/.openplotter/openplotter-settings.json ]; then 36 | cp -f $DIRDATE/OP-signalk/openplotter-settings.json ~/.openplotter/ 37 | fi 38 | if [ ! -f ~/.openplotter/private_unit.json ]; then 39 | cp -f $DIRDATE/classes/private_unit.json ~/.openplotter/ 40 | fi 41 | if [ ! -f ~/.openplotter/SK-simulator.conf ]; then 42 | cp -f $DIRDATE/tools/SK-simulator.conf ~/.openplotter/ 43 | fi 44 | if [ ! -f ~/.openplotter/openplotter_analog.conf ]; then 45 | cp -f $DIRDATE/tools/openplotter_analog.conf ~/.openplotter/ 46 | fi 47 | --------------------------------------------------------------------------------