├── ADS1115 ├── README.md ├── current-differential.py ├── current-singlended-measure.py └── differential_ads1115.py ├── AR300M ├── Readme.md └── wireless ├── Arduino └── espwebserver-current-measurement.ino ├── Barogram ├── Readme.md ├── barogram.png └── influxtest.py ├── CAN NMEA2000 ├── 10-local-rpi.rules └── README.md ├── DS18B20 ├── README.md ├── gui-leds.py ├── gui-testing.py ├── lesut ├── lesut.py ├── logg.py ├── temp-gui.py ├── update-temp-gui.py └── update.py ├── Devices ├── README.md └── openplotter.devices.txt ├── Fileserver ├── Eth0-adhoc-connect.md ├── Readme.md ├── bluetooth.md ├── fstab ├── obexpushd.md ├── smb.conf ├── smb.md └── wifi.md ├── G90 ├── README.md ├── channels.dta ├── maritime-channels └── maritime-channels.png ├── GPSD Position and Time ├── README.md ├── chrony.conf.client ├── chrony.conf.server ├── get-date-from-SignalK.py ├── gpsd ├── gpsd.cliclient.py ├── gpsd.socket ├── ntp.conf ├── set-chrony-from-SignalK.py └── showpos.py ├── Gas-detector ├── MQ-sensors.ino └── README.md ├── IoToB ├── README.md ├── Seatalk │ ├── EspSoftwareSerial-9bit-modified │ │ ├── .gitignore │ │ ├── README.md │ │ ├── UPDATE.md │ │ ├── examples │ │ │ ├── loopback │ │ │ │ └── loopback.ino │ │ │ ├── onewiretest │ │ │ │ └── onewiretest.ino │ │ │ ├── repeater │ │ │ │ └── repeater.ino │ │ │ ├── servoTester │ │ │ │ └── servoTester.ino │ │ │ └── swsertest │ │ │ │ └── swsertest.ino │ │ ├── keywords.txt │ │ ├── library.json │ │ ├── library.properties │ │ └── src │ │ │ ├── SoftwareSerial.cpp │ │ │ ├── SoftwareSerial.cpp~ │ │ │ ├── SoftwareSerial.h │ │ │ └── circular_queue │ │ │ ├── circular_queue.h │ │ │ ├── circular_queue_mp.h │ │ │ └── ghostl.h │ ├── README.md │ ├── Seatalk-Grapher.png │ ├── Seatalk-to-ESP8266_schem.md │ ├── Seatalk-to-ESP8266_schem.png │ ├── SeatalkDataSignalKDemo.ino │ ├── SeatalkDataTest.ino │ └── SoftwareSerialTest.ino ├── Tank-level │ ├── README.md │ ├── WiFiClient-Tank-level-SignalK-v2.ino │ ├── WiFiClient-Tank-level-SignalK-v3.ino │ └── Wifi-tank-level.ino ├── Temperature │ ├── NTC-calibration.ods │ ├── README.md │ ├── Skjema-NTC.png │ ├── Skjema2-NTC.png │ ├── Temperature-NTC.png │ ├── WiFiClient-NTC-v1.1.ino │ └── sensor-box.png ├── Testing-and-Development │ ├── README.md │ ├── WiFiClient-Simulate-wind-data.ino │ ├── WiFiClient-analog-SignalK.ino │ ├── signalK-simulator.py │ ├── signalK-test.py │ ├── sock-UDP-test.py │ └── sock-test.py └── Voltage-and-Current │ ├── README.md │ ├── WiFiClient-U-and-I-SignalK-v2.ino │ ├── WiFiClient-U-and-I-SignalK-v3.ino │ └── WiFiClient-U-and-I-SignalK.ino ├── MCP3008 ├── README.md ├── current-diffmeasure.py ├── current-singlended-measure.py ├── differential.py └── simpletest.py ├── NTP SignalK source ├── get-date-from-SignalK.py └── ntp.conf ├── PCF8574 ├── Readme.md ├── readout.py └── tank-level.py ├── README.md ├── RPi-configfiles ├── Readme.md ├── dhcpcd.conf ├── dnsmasq ├── dnsmasq.conf └── hostapd.conf ├── RPi-settings.md ├── SignalK-tests ├── signalK-simulator.py └── signalK-test.py ├── Winter-monitor ├── crontab ├── dhclient.sh ├── log.sh ├── pwron.py ├── rc.local ├── readme.md └── send-to-thingspeak.py ├── img ├── ADS1115-b.jpg ├── ADS1115-c.jpg ├── ADS1115-d.jpg ├── AIS-receiver.jpg ├── DSC_8967.JPG ├── DSC_8968.JPG ├── DSC_8972.JPG ├── DSC_9061.JPG ├── DSC_9063.JPG ├── DSC_9065.JPG ├── DSC_9068.JPG ├── ESP12E-I-and-U.jpg ├── ESP8266-voltage.jpg ├── Hall-effect-sensors.jpg ├── Hall-sensor-voltage-resistors.jpg ├── I2C-extender.jpg ├── MCP3008-Current-sensor.jpg ├── MCP3008-details.jpg ├── Magnetometer-and-Gyro.jpg ├── NTC-sensors1.JPG ├── PFC8574.jpg ├── README.md ├── Tank-level_bb.png ├── Temp-NTC.png ├── Temperature-NTC.png ├── Temperatures_bb.png ├── UI-ESP32.jpg ├── Water-level-sensor.jpg ├── kompass-gyro-01.jpg └── kompass-gyro-03.jpg ├── pat ├── GRIB.py ├── README.md ├── ardop.png ├── ardop.start ├── config.json ├── get-date-from-SignalK.py ├── get-weather.txt ├── get.grid.py ├── gpsd.config ├── pat-control.py ├── pat-stop.png ├── pat.ardrop.start ├── pat.pid ├── pat.png ├── pat.start ├── pat.stop ├── pat.vara.png ├── pat.vara.start ├── set-date-from-SignalK.py ├── showpos.py └── update.pos.pat.conf.py └── wifi2wifi ├── touch-screen-version ├── Readme.md ├── dhcpcd.conf ├── dnsmasq.conf ├── hostapd ├── hostapd.conf ├── hosts ├── interfaces ├── iptables.ipv4.nat ├── rc.local ├── scan.py └── sysctl.conf └── web-version ├── Readme.md ├── config.php ├── dhcpcd.conf ├── dnsmasq.conf ├── hostapd.conf └── interfaces /ADS1115/README.md: -------------------------------------------------------------------------------- 1 | # ADS1115 16 bits A/D converter 2 | 3 | Files for use with the [ADS1115](https://www.adafruit.com/product/1085) 16 bits Analog to Digital converter chip. 4 | 5 | With 4 inputs with programmable gain (voltage range) and 16 bits resolution it is suitable for high precision measurements 6 | of current, voltage etc. 7 | -------------------------------------------------------------------------------- /ADS1115/current-differential.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time, socket 4 | import Adafruit_ADS1x15 5 | 6 | 7 | # Initiate socket 8 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 9 | 10 | # Create an ADS1115 ADC (16-bit) instance, use a parameter to set another 11 | # address than default 0x48. 12 | 13 | adc = Adafruit_ADS1x15.ADS1115(address=0x49) 14 | 15 | # Choose a gain of 1 for reading voltages from 0 to 4.09V. 16 | # Or pick a different gain to change the range of voltages that are read: 17 | # - 2/3 = +/-6.144V 18 | # - 1 = +/-4.096V 19 | # - 2 = +/-2.048V 20 | # - 4 = +/-1.024V 21 | # - 8 = +/-0.512V 22 | # - 16 = +/-0.256V 23 | # See table 3 in the ADS1015/ADS1115 datasheet for more info on gain. 24 | GAIN = 1 25 | # Maximum voltage is somewhat above this, Vcc - 0.3 which could be 4.7 V if the 26 | # supply voltage is 5V. 27 | 28 | 29 | # Note you can change the differential value to the following: 30 | # - 0 = Channel 0 minus channel 1 31 | # - 1 = Channel 0 minus channel 3 32 | # - 2 = Channel 1 minus channel 3 33 | # - 3 = Channel 2 minus channel 3 34 | 35 | # Samples per second. 36 | SAMPLES=8 37 | 38 | # Differential mode is the most sensible mode for Hall elements which outputs 39 | # vcc/2 at zero voltage. Using a Vin- at Vcc/2 will yield zero voltage difference 40 | # for zero current. A nice match. 41 | # 42 | # There are only 2 single ended channels and only two in differential mode. 43 | # One might concider a MCP3008 to get 4 differential (but limited to 10 bits) 44 | # channels. 45 | 46 | 47 | zero = [0,1] 48 | zero[0]=21 # Given in count from ADC [-32768, 32767], normally close to zero. 49 | zero[1]=12 50 | range = [0,1] 51 | range[0]=8.4 # How many amp per volt, 52 | range[1]=17.3 # slope of the Hall element response curve. 53 | 54 | 55 | while True: 56 | for j in 0,1: 57 | # There are only two inputs using differential mode. 58 | value=adc.read_adc_difference(j*3, gain=GAIN, data_rate=SAMPLES) 59 | u=(float(value-zero[j])/32768.0)*4.096 60 | i=u*range[j] 61 | # print "Channel : ",j,value,u,format(i,'.2f'),"A" 62 | 63 | if j == 0: 64 | SignalK='{"updates": [{"$source": "I2C.ADS1115","values":[ {"path": "electrical.ACS712.current","value":'+format(i,'5.3f')+'}]}]}' 65 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 66 | if j == 1: 67 | SignalK='{"updates": [{"$source": "I2C.ADS1115","values":[ {"path": "electrical.WCS1800.current","value":'+format(i,'5.3f')+'}]}]}' 68 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 69 | 70 | time.sleep(1) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /ADS1115/current-singlended-measure.py: -------------------------------------------------------------------------------- 1 | # Simple example of reading the MCP3008 analog input channels and printing 2 | # them all out. 3 | # Author: Tony DiCola 4 | # License: Public Domain 5 | import time 6 | 7 | # Import SPI library (for hardware SPI) and MCP3008 library. 8 | import Adafruit_GPIO.SPI as SPI 9 | import Adafruit_MCP3008 10 | 11 | 12 | # Software SPI configuration: 13 | CLK = 18 14 | MISO = 23 15 | MOSI = 24 16 | CS = 25 17 | mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) 18 | 19 | # Hardware SPI configuration: 20 | SPI_PORT = 0 21 | SPI_DEVICE = 0 22 | mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 23 | 24 | 25 | while True: 26 | value = mcp.read_adc(1) 27 | i=(value-510)*0.09 28 | print 'Value ',value,' current ',i,' A' 29 | time.sleep(1) 30 | -------------------------------------------------------------------------------- /AR300M/Readme.md: -------------------------------------------------------------------------------- 1 | Setup files for the AR300M mini router. 2 | -------------------------------------------------------------------------------- /AR300M/wireless: -------------------------------------------------------------------------------- 1 | 2 | config wifi-device 'radio0' 3 | option type 'mac80211' 4 | option hwmode '11g' 5 | option path 'platform/qca953x_wmac' 6 | option band '2G' 7 | option htmode 'HT40' 8 | option noscan '1' 9 | option txpower '20' 10 | option channel '6' 11 | 12 | config wifi-iface 'default_radio0' 13 | option device 'radio0' 14 | option network 'lan' 15 | option mode 'ap' 16 | option encryption 'psk2' 17 | option key 'goodlife' 18 | option wds '1' 19 | option ifname 'wlan0' 20 | option ssid 'Algol' 21 | 22 | config wifi-device 'radio1' 23 | option type 'mac80211' 24 | option channel '11' 25 | option hwmode '11g' 26 | option path 'platform/ehci-platform/usb1/1-1/1-1:1.0' 27 | option htmode 'HT20' 28 | option country 'NO' 29 | option legacy_rates '1' 30 | option disabled '0' 31 | 32 | config wifi-iface 'sta' 33 | option device 'radio0' 34 | option network 'wwan' 35 | option mode 'sta' 36 | option ifname 'wlan-sta' 37 | option ssid 'TeamRocketFiber' 38 | option channel '11' 39 | option encryption 'psk2' 40 | option key 'blackpearl' 41 | 42 | -------------------------------------------------------------------------------- /Arduino/espwebserver-current-measurement.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include // ESP module library 5 | #include // Include Emon Library 6 | #include // TM1639 Display module 7 | 8 | SoftwareSerial Serial1(6, 7); // Create a serial instance using pin 6 & 7. 9 | 10 | 11 | char ssid[] = "Mynet"; 12 | char passwd[] = "password"; 13 | int inPinI = 5; // Analog in pin 14 | int status = WL_IDLE_STATUS; 15 | 16 | WiFiEspServer server(80); // Create a server instance 17 | EnergyMonitor emon1; // Create an instance of the energy monitor type 18 | TM1638plus module(8, 10, 9); // define a module on data pin 9, clock pin 10 and strobe pin 8 19 | 20 | void setup() { 21 | pinMode(inPinI,INPUT); 22 | 23 | Serial.begin(115200); // Serial over USB to Arduino IDE 24 | Serial1.begin(9600); // Serial communication to ESP module 25 | 26 | WiFi.init(&Serial1); // Set up serial communication to ESP 8266 27 | emon1.current(inPinI,0); // Current: input pin, calibration. 28 | 29 | Serial.println("Start"); 30 | delay(500); 31 | 32 | 33 | if (WiFi.status() == WL_NO_SHIELD) { 34 | Serial.println("Wifi shield not present"); 35 | while (true) { 36 | delay(500); 37 | Serial.println("No wifi module found"); 38 | } 39 | } 40 | 41 | Serial.println("Trying to connect"); 42 | while (status != WL_CONNECTED) { 43 | Serial.println("Attempt to conncect"); 44 | Serial.println("ssid"); 45 | 46 | status = WiFi.begin(ssid, passwd); 47 | } 48 | 49 | Serial.println("Connected with the following information:"); 50 | printWifiStatus(); 51 | 52 | 53 | Serial.println("Start the web server"); 54 | server.begin(); 55 | 56 | } 57 | 58 | 59 | void loop() { 60 | 61 | WiFiEspClient client = server.available(); 62 | 63 | double Irms, power, voltage=230.0; 64 | int pwdispl; 65 | 66 | Irms = emon1.calcIrms(300); // 1480 samples per sec 67 | pwdispl = (int) (Irms-0.)*voltage; // Read about 1.0 when trafo off 68 | power = (Irms-0.)*voltage; 69 | char cstr[8]; 70 | sprintf(cstr, "%8d", pwdispl); 71 | module.displayText(cstr); 72 | //Serial.println(String(cstr)); 73 | 74 | if (client) { 75 | Serial.println("New client"); 76 | 77 | boolean currentLineIsBlank = true; 78 | 79 | while(client.connected()) { 80 | if (client.available()) { 81 | char c = client.read(); 82 | //Serial.write(c); 83 | 84 | if (c == '\n' && currentLineIsBlank) { 85 | //Serial.println(power); 86 | //Serial.println("Sending response"); 87 | client.print( 88 | "HTTP/1.1 200 OK\r\n" 89 | "Content-Type: text/html\r\n" 90 | "Connection: close\r\n" 91 | "\r\n"); 92 | client.print("\r\n"); 93 | client.print("\r\n"); 94 | client.print("\r\n"); 95 | client.print("H4K\r\n"); 96 | client.print("\r\n"); 97 | client.print("\r\n"); 98 | client.print("

H4k effekt

\r\n"); 99 | client.print("

Effekt :

\r\n"); 100 | client.print(power); 101 | client.print(" Watt\r\n"); 102 | client.print("\r\n"); 103 | client.print("\r\n"); 104 | break; 105 | } 106 | if (c == '\n') { 107 | currentLineIsBlank = true; 108 | } 109 | else if (c != '\r') { 110 | currentLineIsBlank = false; 111 | } 112 | } 113 | } 114 | delay(10); 115 | client.stop(); 116 | //Serial.println("Client disconnected"); 117 | } 118 | 119 | } 120 | 121 | 122 | 123 | 124 | void printWifiStatus() { 125 | Serial.print("SSID "); Serial.println(WiFi.SSID()); 126 | IPAddress ip = WiFi.localIP(); 127 | Serial.print("IP address "); Serial.println(ip); 128 | } 129 | 130 | 131 | -------------------------------------------------------------------------------- /Barogram/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Barogram 3 | 4 | A simple Python script to make a barogram plot from data in the influx data base. An expercise in uisng Python to 5 | interact with the influx data base and plot a graph of the air pressure the last X hours. 6 | 7 | While both Dashboards and Grafana do an excellent job, this is more an exersise in learning how Python interact with influxdb. 8 | In addition some data massage preparing for plotting. 9 | -------------------------------------------------------------------------------- /Barogram/barogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/Barogram/barogram.png -------------------------------------------------------------------------------- /Barogram/influxtest.py: -------------------------------------------------------------------------------- 1 | import time 2 | import dateutil.parser 3 | import matplotlib.pyplot as plt 4 | from influxdb import InfluxDBClient 5 | 6 | client = InfluxDBClient(host='localhost', port=8086) 7 | client.switch_database('boatdata') 8 | 9 | results=client.query('select mean("value") AS "mean_value" from "environment.outside.pressure" WHERE time > now()-24h group by time(30m) fill(none)') 10 | 11 | #print(results.raw) 12 | dx={} 13 | dy={} 14 | points = results.get_points() 15 | 16 | j=0 17 | for item in points: 18 | # print(item['time']) 19 | ts=item['time'] # Keep the last timestamp, this is now, goes on the header of plot. 20 | dt = dateutil.parser.parse(item['time']) 21 | # print(int(time.mktime(dt.timetuple()))) 22 | dx[j]=int(time.mktime(dt.timetuple())) 23 | # print(item['mean_value']) 24 | dy[j]=item['mean_value'] 25 | j=j+1 26 | 27 | #print(ts) 28 | j=j-1 29 | #print(len(dx)) 30 | x=[0]*j 31 | y=[0]*j 32 | #print(j) 33 | for i in range(j): 34 | # print(j,i,dx[i]) 35 | x[i]=(dx[i]-dx[j])/3600 36 | y[i]=dy[i]/100+17 # Kjelsås 155moh P=P0*exp(-155/8300) 37 | # print(x[i]) 38 | # print(y[i]) 39 | 40 | plt.plot(x,y,'bo') 41 | plt.xlabel('hours bp') 42 | plt.ylabel('Pressure [hPa]') 43 | plt.title('Barogram at '+ts[:-4].replace('T',' ')+' UTC') 44 | plt.savefig('barogram.png') 45 | plt.show() 46 | 47 | -------------------------------------------------------------------------------- /CAN NMEA2000/10-local-rpi.rules: -------------------------------------------------------------------------------- 1 | KERNEL=="vchiq", GROUP="video", MODE="0660" 2 | KERNEL=="vcsm-cma", GROUP="video", MODE="0660" 3 | KERNEL=="vcio", GROUP="video", MODE="0660" 4 | 5 | SUBSYSTEM=="rpivid-*", GROUP="video", MODE="0660" 6 | SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" 7 | 8 | 9 | # These entries go into the rule file as 'idVendor' and 'idProduct' . 10 | ATTRS{idVendor}=="ad50", ATTRS{idProduct}=="60c4", SYMLINK="canable%n" 11 | 12 | 13 | -------------------------------------------------------------------------------- /CAN NMEA2000/README.md: -------------------------------------------------------------------------------- 1 | # Interfacing to CANbus / NMEA2000 2 | 3 | ## Introduction 4 | Interfacing CANbus (Controller Area Network) or NMEA2000 to 5 | OpenPlotter allows you to integrate your marine navigation and 6 | communication systems with your OpenPlotter setup. CANbus and NMEA2000 7 | are both widely used communication protocols in the marine 8 | industry. They enable devices like chartplotters, GPS receivers, 9 | sensors, and other marine instruments to exchange data and work 10 | together seamlessly. 11 | 12 | The CANable device is a popular USB-to-CAN adapter that allows you to 13 | connect your computer to a Controller Area Network (CAN) bus. It is a 14 | compact and affordable device that provides a simple way to interface 15 | with CAN networks for various applications, including automotive, 16 | industrial, and marine systems. 17 | 18 | The CANable device is based on the Microchip MCP2515 CAN controller 19 | and MCP2551 CAN transceiver. It offers a USB interface for easy 20 | connectivity to your computer and supports both CAN 2.0A (11-bit 21 | identifier) and CAN 2.0B (29-bit identifier) protocols. 22 | 23 | With the CANable device, you can integrate CAN bus functionality into 24 | your OpenPlotter setup. By connecting the CANable adapter to your 25 | Raspberry Pi running OpenPlotter, you can interface with CAN-enabled 26 | marine devices, retrieve data from the network, and utilize it within 27 | the OpenPlotter ecosystem. This enables you to access and process data 28 | from instruments like chartplotters, engine monitors, sensors, and 29 | more, enhancing your marine navigation, monitoring, and automation 30 | capabilities. 31 | 32 | 33 | ## Using the Canable device 34 | 35 | The [canable](https://canable.io/) can translate the CANbus messages and data to a serial Linux device. 36 | This device will manifest itself as a ```/dev/ttyACM0``` (og 1,2 etc if many devices are connected). 37 | 38 | In openplotter dialog window this device could be selected, but that is nor always a good solution as the 39 | *ttyACMx* number can change. A far better option is to make a udev entry and give the canable device a 40 | proper name in the ```/dev/``` directory, my coice is 'canable'. 41 | 42 | ### Making a udev entry 43 | The [udev](https://en.wikipedia.org/wiki/Udev) is a Linux subsystem 44 | that manages the device nodes in the ```/dev``` directory. It is 45 | responsible for handling the dynamic creation and management of device 46 | nodes as devices are connected or disconnected from the system. udev 47 | allows for automatic device recognition and configuration, making it 48 | easier to manage hardware devices in a Linux environment. 49 | 50 | udev operates based on a set of rules defined in configuration 51 | files. These rules match devices based on their attributes and provide 52 | instructions on how to handle them. 53 | 54 | To make a new udev entry one need to find the right numbers for the device, 55 | assuming that the canable device came up as ```/dev/ttyACM0``` : 56 | ``` 57 | udevadm info --query=all --name=/dev/ttyACM0 | grep ID_VENDOR_ID 58 | E: ID_VENDOR_ID=ad50 59 | udevadm info --query=all --name=/dev/ttyACM0 | grep ID_MODEL_ID 60 | E: ID_MODEL_ID=60c4 61 | ``` 62 | The numbers differ from the ones given on the canable [web page](https://canable.io/updater/udev.html). 63 | If the pipe grep is omitted text identifying the device will be displayed, nice if ```ttyACM0``` is not 64 | the canable device. 65 | 66 | The udev rules files are found at : ```/lib/udev/rules.d/``` and the file 67 | ```10-local-rpi.rules``` is used for local rules. Append the line : 68 | ``` 69 | ATTRS{idVendor}=="ad50", ATTRS{idProduct}=="60c4", SYMLINK="canable%n" 70 | ``` 71 | to the ```/lib/udev/rules.d/10-local-rpi.rules``` and run the command 72 | ``` 73 | udevadm trigger 74 | ``` 75 | if the Vendor and Product match the values found when the device report in you should now have 76 | a new device in the dev directory, ```/dev/canablex``` (x might be 0, 1, 2, I got ```/dev/canable1``` 77 | and ```/dev/canable2```). They are : 78 | ``` 79 | root@OpenPlotter:/lib/udev/rules.d# ls -l /dev/cana* 80 | lrwxrwxrwx 1 root root 7 juni 3 12:18 /dev/canable1 -> ttyACM1 81 | lrwxrwxrwx 1 root root 15 juni 3 12:18 /dev/canable2 -> bus/usb/001/004 82 | ``` 83 | One is a link to the USB port while the other is a link to the ```ttyACM1``` device. I use *canable1* in 84 | Openplotter. 85 | 86 | Now try a reboot and check if all devices and entries come up as expected and that all interfacing 87 | with OpenPlotter work. 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /DS18B20/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DS18B20/gui-leds.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | import os 3 | import glob 4 | import RPi.GPIO as GPIO 5 | 6 | os.system('modprobe w1-gpio') 7 | os.system('modprobe w1-therm') 8 | 9 | 10 | GPIO.setmode(GPIO.BOARD) 11 | RED_LED = 18 12 | GRE_LED = 16 13 | BLU_LED = 12 14 | GPIO.setup(RED_LED, GPIO.OUT) 15 | GPIO.setup(GRE_LED, GPIO.OUT) 16 | GPIO.setup(BLU_LED, GPIO.OUT) 17 | 18 | device_folder=[1,2,3] 19 | device_file=[1,2,3] 20 | 21 | base_dir = '/sys/bus/w1/devices/' 22 | 23 | for j in 1,2: 24 | # print(j) 25 | device_folder[j] = glob.glob(base_dir + '28*')[j-1] 26 | # print("device_folder", device_folder[j]) 27 | device_file[j] = device_folder[j] + '/w1_slave' 28 | 29 | def read_temp_raw(j): 30 | f = open(device_file[j], 'r') 31 | lines = f.readlines() 32 | f.close() 33 | return lines 34 | 35 | def read_temp(j): 36 | lines = read_temp_raw(j) 37 | while lines[0].strip()[-3:] != 'YES': 38 | time.sleep(0.2) 39 | lines = read_temp_raw(j) 40 | equals_pos = lines[1].find('t=') 41 | if equals_pos != -1: 42 | temp_string = lines[1][equals_pos+2:] 43 | temp_c = float(temp_string) / 1000.0 44 | return temp_c 45 | 46 | 47 | root = Tk() 48 | root.title('Temperaturer') 49 | 50 | def updateTime() : 51 | t1=read_temp(1) 52 | t2=read_temp(2) 53 | if t1<20: 54 | GPIO.output(BLU_LED, True) 55 | GPIO.output(GRE_LED, False) 56 | GPIO.output(RED_LED, False) 57 | if t1>20 and t1<23: 58 | GPIO.output(BLU_LED, False) 59 | GPIO.output(GRE_LED, True) 60 | GPIO.output(RED_LED, False) 61 | 62 | if t1>23: 63 | GPIO.output(BLU_LED, False) 64 | GPIO.output(GRE_LED, False) 65 | GPIO.output(RED_LED, True) 66 | msg = "Temp1: "+"{:3.1f}".format(t1)+"\u2103\n" 67 | msg=msg+"Temp2: "+"{:3.1f}".format(t1)+"\u2103" 68 | # print(msg) 69 | v.set(msg) 70 | root.after(2000, updateTime) 71 | 72 | v = StringVar() 73 | Label(root, textvariable=v, font=("Helvetica", 30)).pack() 74 | v.set('--.-') 75 | 76 | root.after(2, updateTime) 77 | root.mainloop() 78 | 79 | -------------------------------------------------------------------------------- /DS18B20/gui-testing.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | import os 3 | import glob 4 | 5 | os.system('modprobe w1-gpio') 6 | os.system('modprobe w1-therm') 7 | 8 | device_folder=[1,2,3] 9 | device_file=[1,2,3] 10 | 11 | base_dir = '/sys/bus/w1/devices/' 12 | 13 | for j in 1,2: 14 | # print(j) 15 | device_folder[j] = glob.glob(base_dir + '28*')[j-1] 16 | # print("device_folder", device_folder[j]) 17 | device_file[j] = device_folder[j] + '/w1_slave' 18 | 19 | def read_temp_raw(j): 20 | f = open(device_file[j], 'r') 21 | lines = f.readlines() 22 | f.close() 23 | return lines 24 | 25 | def read_temp(j): 26 | lines = read_temp_raw(j) 27 | while lines[0].strip()[-3:] != 'YES': 28 | time.sleep(0.2) 29 | lines = read_temp_raw(j) 30 | equals_pos = lines[1].find('t=') 31 | if equals_pos != -1: 32 | temp_string = lines[1][equals_pos+2:] 33 | temp_c = float(temp_string) / 1000.0 34 | return temp_c 35 | 36 | 37 | root = Tk() 38 | root.title('Temperaturer') 39 | 40 | def updateTime() : 41 | msg = "Temp1: "+"{:3.1f}".format(read_temp(1))+"\u2103\n" 42 | msg=msg+"Temp2: "+"{:3.1f}".format(read_temp(2))+"\u2103" 43 | # print(msg) 44 | v.set(msg) 45 | root.after(2000, updateTime) 46 | 47 | v = StringVar() 48 | Label(root, textvariable=v, font=("Helvetica", 30)).pack() 49 | v.set('--.-') 50 | 51 | root.after(2, updateTime) 52 | root.mainloop() 53 | 54 | -------------------------------------------------------------------------------- /DS18B20/lesut: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import glob 5 | import time 6 | 7 | os.system('modprobe w1-gpio') 8 | os.system('modprobe w1-therm') 9 | 10 | device_folder=[1,2,3] 11 | device_file=[1,2,3] 12 | 13 | base_dir = '/sys/bus/w1/devices/' 14 | for j in 1,2: 15 | print(j) 16 | device_folder[j] = glob.glob(base_dir + '28*')[j-1] 17 | print("device_folder", device_folder[j]) 18 | device_file[j] = device_folder[j] + '/w1_slave' 19 | 20 | def read_temp_raw(j): 21 | f = open(device_file[j], 'r') 22 | lines = f.readlines() 23 | f.close() 24 | return lines 25 | 26 | def read_temp(j): 27 | lines = read_temp_raw(j) 28 | while lines[0].strip()[-3:] != 'YES': 29 | time.sleep(0.2) 30 | lines = read_temp_raw(j) 31 | equals_pos = lines[1].find('t=') 32 | if equals_pos != -1: 33 | temp_string = lines[1][equals_pos+2:] 34 | temp_c = float(temp_string) / 1000.0 35 | return temp_c 36 | 37 | 38 | temp=[1,2,3] 39 | while True: 40 | temp[1]=read_temp(1) 41 | temp[2]=read_temp(2) 42 | print("Temperatur 1 :", temp[1]," C temp 2",temp[2]," C") 43 | time.sleep(2) 44 | -------------------------------------------------------------------------------- /DS18B20/lesut.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import glob 5 | import time 6 | 7 | os.system('modprobe w1-gpio') 8 | os.system('modprobe w1-therm') 9 | 10 | base_dir = '/sys/bus/w1/devices/' 11 | device_folder = glob.glob(base_dir + '28*')[0] 12 | print("device_folder", device_folder) 13 | device_file = device_folder + '/w1_slave' 14 | 15 | def read_temp_raw(): 16 | f = open(device_file, 'r') 17 | lines = f.readlines() 18 | f.close() 19 | return lines 20 | 21 | def read_temp(): 22 | lines = read_temp_raw() 23 | while lines[0].strip()[-3:] != 'YES': 24 | time.sleep(0.2) 25 | lines = read_temp_raw() 26 | equals_pos = lines[1].find('t=') 27 | if equals_pos != -1: 28 | temp_string = lines[1][equals_pos+2:] 29 | temp_c = float(temp_string) / 1000.0 30 | return temp_c 31 | 32 | while True: 33 | temp=read_temp() 34 | print("Temperatur :", temp," C") 35 | time.sleep(1) 36 | -------------------------------------------------------------------------------- /DS18B20/logg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import os 5 | import glob 6 | import time 7 | 8 | os.system('modprobe w1-gpio') 9 | os.system('modprobe w1-therm') 10 | 11 | base_dir = '/sys/bus/w1/devices/' 12 | device_folder = glob.glob(base_dir + '28*')[0] 13 | print("device_folder", device_folder) 14 | device_file = device_folder + '/w1_slave' 15 | 16 | def read_temp_raw(): 17 | f = open(device_file, 'r') 18 | lines = f.readlines() 19 | f.close() 20 | return lines 21 | 22 | def read_temp(): 23 | lines = read_temp_raw() 24 | while lines[0].strip()[-3:] != 'YES': 25 | time.sleep(0.2) 26 | lines = read_temp_raw() 27 | equals_pos = lines[1].find('t=') 28 | if equals_pos != -1: 29 | temp_string = lines[1][equals_pos+2:] 30 | temp_c = float(temp_string) / 1000.0 31 | return temp_c 32 | 33 | while True: 34 | temp=read_temp() 35 | if temp > 27: 36 | print("Temperatur :", temp," C") 37 | time.sleep(2) 38 | -------------------------------------------------------------------------------- /DS18B20/temp-gui.py: -------------------------------------------------------------------------------- 1 | """ 2 | temp-gui.py 3 | ~~~~~~ 4 | 5 | Creates a simple GUI for displaying two temps. 6 | """ 7 | 8 | import tkinter 9 | from tkinter import ttk 10 | 11 | import os 12 | import glob 13 | import time 14 | 15 | class Temps(ttk.Frame): 16 | """The temp gui and functions.""" 17 | def __init__(self, parent, *args, **kwargs): 18 | ttk.Frame.__init__(self, parent, *args, **kwargs) 19 | self.root = parent 20 | self.init_gui() 21 | 22 | 23 | def get_data(self): 24 | self.temp1_label['text'] = read_temp(1) 25 | self.temp2_label['text'] = read_temp(2) 26 | 27 | 28 | def on_quit(self): 29 | """Exits program.""" 30 | quit() 31 | 32 | def init_gui(self): 33 | """Builds GUI.""" 34 | self.root.title('Temperaturer') 35 | self.root.option_add('*tearOff', 'FALSE') 36 | self.grid(column=0, row=0, sticky='nsew') 37 | self.menubar = tkinter.Menu(self.root) 38 | self.menu_file = tkinter.Menu(self.menubar) 39 | self.menu_file.add_command(label='Exit', command=self.on_quit) 40 | self.menubar.add_cascade(menu=self.menu_file, label='File') 41 | self.root.config(menu=self.menubar) 42 | 43 | self.temp1_frame = ttk.LabelFrame(self, text='Temp', height=100) 44 | self.temp1_frame.grid(column=0, row=4, columnspan=4, sticky='nesw') 45 | 46 | self.temp1_label = ttk.Label(self.temp1_frame, text='') 47 | self.temp1_label.grid(column=0, row=0) 48 | 49 | self.temp2_frame = ttk.LabelFrame(self, text='Temp', height=100) 50 | self.temp2_frame.grid(column=1, row=4, columnspan=4, sticky='nesw') 51 | 52 | self.temp2_label = ttk.Label(self.temp2_frame, text='') 53 | self.temp2_label.grid(column=1, row=0) 54 | 55 | self.tempdata() 56 | 57 | 58 | # Labels that remain constant throughout execution. 59 | ttk.Label(self, text='Temperaturer').grid(column=0, row=0, 60 | columnspan=4) 61 | ttk.Label(self, text=' Pult ').grid(column=0, row=2, sticky='w') 62 | ttk.Label(self, text=' Motor ').grid(column=2, row=2, sticky='w') 63 | ttk.Separator(self, orient='horizontal').grid(column=0, 64 | row=1, columnspan=4, sticky='ew') 65 | for child in self.winfo_children(): 66 | child.grid_configure(padx=5, pady=5) 67 | 68 | def tempdata(self): 69 | self.temp1_frame = ttk.LabelFrame(self, text='Temp1', height=100) 70 | self.temp1_frame.grid(column=0, row=4, columnspan=4, sticky='nesw') 71 | self.temp1_label = ttk.Label(self.temp1_frame, text='') 72 | self.temp1_label.grid(column=0, row=0) 73 | self.temp2_frame = ttk.LabelFrame(self, text='Temp2', height=100) 74 | self.temp2_frame.grid(column=1, row=4, columnspan=4, sticky='nesw') 75 | self.temp2_label = ttk.Label(self.temp2_frame, text='') 76 | self.temp2_label.grid(column=1, row=0) 77 | self.temp1_label['text'] = read_temp(1) 78 | self.temp2_label['text'] = read_temp(2) 79 | 80 | def update(event = None): 81 | self.update_idletasks() 82 | self.temp1_label['text'] = read_temp(1) 83 | self.temp2_label['text'] = read_temp(2) 84 | self.after(2000,self.update) 85 | 86 | 87 | 88 | # program start here 89 | 90 | os.system('modprobe w1-gpio') 91 | os.system('modprobe w1-therm') 92 | 93 | device_folder=[1,2,3] 94 | device_file=[1,2,3] 95 | 96 | base_dir = '/sys/bus/w1/devices/' 97 | for j in 1,2: 98 | print(j) 99 | device_folder[j] = glob.glob(base_dir + '28*')[j-1] 100 | print("device_folder", device_folder[j]) 101 | device_file[j] = device_folder[j] + '/w1_slave' 102 | 103 | def read_temp_raw(j): 104 | f = open(device_file[j], 'r') 105 | lines = f.readlines() 106 | f.close() 107 | return lines 108 | 109 | def read_temp(j): 110 | lines = read_temp_raw(j) 111 | while lines[0].strip()[-3:] != 'YES': 112 | time.sleep(0.2) 113 | lines = read_temp_raw(j) 114 | equals_pos = lines[1].find('t=') 115 | if equals_pos != -1: 116 | temp_string = lines[1][equals_pos+2:] 117 | temp_c = float(temp_string) / 1000.0 118 | return temp_c 119 | 120 | 121 | temp=[1,2,3] 122 | 123 | 124 | print(read_temp(1)) 125 | print(read_temp(2)) 126 | 127 | if __name__ == '__main__': 128 | root = tkinter.Tk() 129 | Temps(root) 130 | root.update() 131 | root.mainloop() 132 | 133 | -------------------------------------------------------------------------------- /DS18B20/update-temp-gui.py: -------------------------------------------------------------------------------- 1 | import tkinter 2 | from tkinter import ttk 3 | import os 4 | import glob 5 | import time 6 | 7 | main = tkinter.Tk() 8 | Temps = tkinter.Text(main) 9 | main.title('Temperaturer') 10 | main.option_add('*tearOff', 'FALSE') 11 | Temps.grid(column=0, row=0, sticky='nsew') 12 | 13 | #Temps.grid() 14 | 15 | os.system('modprobe w1-gpio') 16 | os.system('modprobe w1-therm') 17 | 18 | device_folder=[1,2,3] 19 | device_file=[1,2,3] 20 | 21 | base_dir = '/sys/bus/w1/devices/' 22 | 23 | for j in 1,2: 24 | print(j) 25 | device_folder[j] = glob.glob(base_dir + '28*')[j-1] 26 | print("device_folder", device_folder[j]) 27 | device_file[j] = device_folder[j] + '/w1_slave' 28 | 29 | def read_temp_raw(j): 30 | f = open(device_file[j], 'r') 31 | lines = f.readlines() 32 | f.close() 33 | return lines 34 | 35 | def read_temp(j): 36 | lines = read_temp_raw(j) 37 | while lines[0].strip()[-3:] != 'YES': 38 | time.sleep(0.2) 39 | lines = read_temp_raw(j) 40 | equals_pos = lines[1].find('t=') 41 | if equals_pos != -1: 42 | temp_string = lines[1][equals_pos+2:] 43 | temp_c = float(temp_string) / 1000.0 44 | return temp_c 45 | 46 | 47 | def update_temps(event = None): 48 | Temps.temp1_label['text'] = read_temp(1) 49 | Temps.temp2_label['text'] = read_temp(2) 50 | Temps.update_idletasks() 51 | print("hei") 52 | Temps.after(2000,update_temps) 53 | 54 | 55 | ttk.Separator(Temps, orient='horizontal').grid(column=0, 56 | row=1, columnspan=4, sticky='ew') 57 | for child in Temps.winfo_children(): 58 | child.grid_configure(padx=30, pady=0) 59 | # print(child) 60 | 61 | 62 | Temps.temp1_frame = ttk.LabelFrame(main, text='Temp1', height=100) 63 | Temps.temp1_frame.grid(column=0, row=4, columnspan=4, sticky='nesw') 64 | Temps.temp1_label = ttk.Label(Temps.temp1_frame, text='') 65 | Temps.temp1_label.grid(column=0, row=0) 66 | 67 | Temps.temp2_frame = ttk.LabelFrame(main, text='Temp2', height=100) 68 | Temps.temp2_frame.grid(column=1, row=4, columnspan=4, sticky='nesw') 69 | Temps.temp2_label = ttk.Label(Temps.temp2_frame, text='') 70 | Temps.temp2_label.grid(column=1, row=0) 71 | 72 | Temps.temp1_label['text'] = read_temp(1) 73 | Temps.temp2_label['text'] = read_temp(2) 74 | 75 | update_temps() 76 | main.mainloop() 77 | -------------------------------------------------------------------------------- /DS18B20/update.py: -------------------------------------------------------------------------------- 1 | import tkinter 2 | from time import sleep 3 | 4 | main = tkinter.Tk() 5 | txt = tkinter.Text(main) 6 | txt.grid() 7 | def update_txt(event = None): 8 | vals = ['This is some text.', 9 | 'This is some more.', 10 | 'Blah blah blah'] 11 | i = 0 12 | while i < len(vals): 13 | txt.delete('1.0','end') 14 | txt.insert('1.0',vals[i]) 15 | txt.update_idletasks() 16 | sleep(2) 17 | i=i+1 18 | 19 | main.after(1000,update_txt) 20 | main.mainloop() 21 | -------------------------------------------------------------------------------- /Devices/README.md: -------------------------------------------------------------------------------- 1 | # Device management 2 | 3 | The file openplotter.devices.txt contain a list of devices and some examples to 4 | manage them. One do not want the linke and names to point to different devices each time the system 5 | is powered up. In addition some devives require rules how to deal with them. 6 | 7 | Some rules have to be writted on edited, the rules are located at : /lib/udev/rules.d 8 | 9 | The file should provide enough hints to help you continue. 10 | 11 | 12 | -------------------------------------------------------------------------------- /Fileserver/Eth0-adhoc-connect.md: -------------------------------------------------------------------------------- 1 | # Ethernet setup 2 | 3 | ## Ad hoc setup for cable ethernet 4 | When encounter a new wifi network where SSID and password need to be entered into the OrangePi 5 | server a cable can be used between the laptop (which provide both SSID and password, as we need 6 | to enter it into the OragePi). 7 | 8 | Just connect the units with a RJ45 cable and select "Shared with other computers" instead of the 9 | more common "Automatic (DHCP)". After a few seconds the ifconfig command will show an ipaddress 10 | on the eth0, ifconfig eth0. 11 | ``` 12 | service restart network 13 | ``` 14 | and the orange pi should now be on the wifi net with as assigned ip from the DHCP server. You can 15 | use the arp -a command to find it, or log in via the RJ45 cable from the laptop. 16 | 17 | This is the laptop's eth0 ad-hoc network address. To find the OrangePi units's address we need to 18 | issue an arp comand, arc -a. It will whow an ip address associated with eth0. 19 | 20 | Then it's simple matter of logging in to the OrangePi using ssh. 21 | 22 | Use ssh ip-address to log in as root or orangepi user and edit the 23 | config files, 24 | ``` 25 | nano /etc/network/interfaces 26 | ``` 27 | and update the SSID and password as needed. 28 | 29 | -------------------------------------------------------------------------------- /Fileserver/Readme.md: -------------------------------------------------------------------------------- 1 | # File server 2 | 3 | ## Project page 4 | Exchange of photos and multimedia files on board. See the 5 | [web page](https://sites.google.com/site/olewsaa/yacht-server/file-server---network-file-system-nfs) about the file server for some more information. 6 | 7 | 8 | ## Background 9 | Very often files and photos need to be shared and exchanged. This project sets up a very small file server using Bluetooth, SAMBA, NFS and sshFS/SFTP to enable laptops, phones and pads to upload, download, share and exchange photos, music and other files. 10 | 11 | ## Implementation 12 | 13 | Connection over wifi and bluetooth for mobile phones. Wifi require an app like andSMB to be installed, while bluetooth 14 | just works witout any extra app installed. 15 | 16 | It's also an option to connect a laptop via an ethernet cable and use an adhoc network. This needed to enter 17 | SSID and password into the orangepi. 18 | 19 | 20 | -------------------------------------------------------------------------------- /Fileserver/bluetooth.md: -------------------------------------------------------------------------------- 1 | # Bluetooth setup 2 | 3 | ## Dsiribution used 4 | 5 | [https://www.armbian.com/orange-pi-zero/#kernels-archive] 6 | Running : Armbian_5.38_Orangepizero_Debian_stretch_next_4.14.14 7 | 8 | ## Instructions 9 | 10 | Bluetooth server for sharing of files and photos 11 | 12 | ### Background web sites 13 | [http://www.instructables.com/id/Bluetooth-How-to-send-a-copy-of-your-photos-and-vi/] 14 | [http://www.instructables.com/id/Install-Bluetooth-in-Linux-System/] 15 | 16 | ### Step by step instructions 17 | 18 | Step 1: 19 | [http://www.instructables.com/id/Install-Bluetooth-in-Linux-System/] 20 | ``` 21 | apt-get update 22 | 23 | apt-cache show bluez 24 | service bluetooth start 25 | service bluetooth status 26 | bt-adapter -l 27 | hciconfig -a 28 | hcitool dev 29 | hcitool scan 30 | 31 | service dbus status 32 | service bluetooth status 33 | hciconfig -a 34 | ``` 35 | Step 2: 36 | [http://www.instructables.com/id/Make-Raspberry-Pi-Discoverable-By-Remote-Bluetooth/] 37 | ``` 38 | hciconfig -a 39 | hciconfig hci0 piscan 40 | hciconfig -a hci0 | grep -i Name 41 | ``` 42 | Step 3: 43 | [http://www.instructables.com/id/Bluetooth-How-to-send-a-copy-of-your-photos-and-vi/] 44 | ``` 45 | apt-get install obexpushd 46 | ps aux | grep -i obexpushd ; kill processes. 47 | ``` 48 | Edit : /etc/systemd/system/dbus-org.bluez.service 49 | add --compat 50 | ``` 51 | ExecStart=/usr/lib/bluetooth/bluetoothd --compat --noplugin=sap 52 | ``` 53 | From file: /etc/bluetooth/main.conf 54 | ``` 55 | # How long to stay in discoverable mode before going back to non-discoverable 56 | # The value is in seconds. Default is 180, i.e. 3 minutes. 57 | # 0 = disable timer, i.e. stay discoverable forever 58 | DiscoverableTimeout = 0 59 | ``` 60 | Start the service 61 | ``` 62 | systemctl daemon-reload 63 | systemctl restart bluetooth 64 | obexpushd -B -n -o '/home/pi/storage' # This is for testing, use the service obexpushd 65 | # described in another file. 66 | chmod a+rwx /home/pi/storage/ 67 | chmod a+rx /home/pi 68 | ``` 69 | To automatically enable services after reboot : 70 | ``` 71 | systemctl enable bluetooth 72 | ``` 73 | This should start the service at boot time. 74 | 75 | 76 | 77 | 78 | 79 | Alternatives to do this, not tested by me : 80 | https://askubuntu.com/questions/131570/how-do-you-make-ubuntu-accept-files-sent- 81 | over-bluetooth 82 | 83 | 84 | -------------------------------------------------------------------------------- /Fileserver/fstab: -------------------------------------------------------------------------------- 1 | The file /etc/fstab lists file syemsts to be mounted. 2 | 3 | This is an example of a very simple /etc/fstab: 4 | # 5 | # /storage ; make sure everybody can read and write 6 | /dev/sda /storage vfat rw,user,exec,umask=000 0 0 7 | 8 | 9 | -------------------------------------------------------------------------------- /Fileserver/obexpushd.md: -------------------------------------------------------------------------------- 1 | # Bluetooth service 2 | 3 | ## Instructions 4 | 5 | Edit the file : 6 | nano /etc/systemd/system/obexpush.service 7 | to include lines below. 8 | ``` 9 | [Unit] 10 | Description=OBEX Push service 11 | After=bluetooth.service 12 | Requires=bluetooth.service 13 | 14 | [Service] 15 | ExecStart=/usr/bin/obexpushd -B -n -o /storage 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | ``` 20 | nano /lib/systemd/system/obexpushd.service 21 | 22 | Same file as above, cp is also ok. 23 | 24 | Then start the services: 25 | ``` 26 | systemctl enable obexpush 27 | service obexpushd start 28 | ``` 29 | 30 | Set up storage. See also the file bluetooth.md. 31 | ``` 32 | cat /proc/partitions 33 | nano /etc/fstab 34 | mount -a 35 | df -h 36 | ls /storage/ 37 | ``` 38 | -------------------------------------------------------------------------------- /Fileserver/smb.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | workgroup = WORKGROUP 3 | netbios name = Filer 4 | wins support = true 5 | domain logons = Yes 6 | comment = File Server 7 | server string = File Server 8 | dns proxy = No 9 | [storage] 10 | comment = storage 11 | path = /storage 12 | security = user 13 | read only = no 14 | writable = yes 15 | public = Yes 16 | -------------------------------------------------------------------------------- /Fileserver/smb.md: -------------------------------------------------------------------------------- 1 | # Sambe file server 2 | 3 | Installing samba is straightforwared and well covered on the net. 4 | ``` 5 | smbpasswd -a guest 6 | ``` 7 | The only thing to remember is that the samba user must have a linux user entry with the same 8 | name (not needed fo rsamba v. 4). 9 | 10 | The USB disk or stick need to be mounted at boot time, remember to update the /etc/fstab. 11 | To autostart samba at boot the following command must be issued. 12 | systemctl enable samba 13 | 14 | -------------------------------------------------------------------------------- /Fileserver/wifi.md: -------------------------------------------------------------------------------- 1 | # Wifi setup 2 | 3 | 4 | Edit the interfaces: 5 | ``` 6 | nano /etc/network/interfaces 7 | ``` 8 | The file should look like : 9 | ``` 10 | source-directory /etc/network/interfaces.d 11 | auto lo eth0 12 | allow-hotplug eth0 13 | iface lo inet loopback 14 | iface eth0 inet dhcp 15 | 16 | auto wlan0 17 | iface wlan0 inet dhcp 18 | wpa-ssid TeamRocketHQ 19 | wpa-psk password 20 | ``` 21 | 22 | Change SSID and password to fit your needs. 23 | -------------------------------------------------------------------------------- /G90/README.md: -------------------------------------------------------------------------------- 1 | # Scripts for my Xiegu G90 2 | 3 | My Xiegu G90 is installed on board Algol. Both marine call sign LG3328 4 | and my ham call sign LB4PJ. 5 | 6 | 7 | ## Dual frequency marine channels 8 | 9 | Some scripts to facilitate dual frequency marine channels as the 10 | memory cannot set both A and B. 11 | 12 | You still need to swap A/B manually and run tune as the rigctld do not 13 | support tune for flrig/G90. 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /G90/maritime-channels: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # 4 | # Script to set Maritime ITA channels frequency 5 | # These MF & HF working channels are duplex channels 6 | # require split mode and setting VFO A and VFO B. 7 | # 8 | # Used for Xiegu G90, but as flrig is used to control the 9 | # radio it should be fairly portable. 10 | # 11 | # Ole W. Saastad, LB4PJ 12 | # v0.1 31 Mar 2022 13 | # v0.2 1 Apr 2022 14 | # 15 | 16 | import sys 17 | import os 18 | import time 19 | import tkinter as tk 20 | from tkinter import simpledialog 21 | 22 | # Maritime working channel frequencies imported from file 23 | 24 | with open('channels.dta', 'r') as infile: 25 | fq = {}; 26 | for line in infile: 27 | ch, rxfrq, txfrq = line.strip().split(' ') 28 | if ch not in fq: 29 | fq[ch]={} 30 | fq[ch]['rx'] = rxfrq 31 | fq[ch]['tx'] = txfrq 32 | else : 33 | print("Channel already assigned, skipping channel",ch) 34 | infile.close() 35 | 36 | root = tk.Tk() 37 | root.withdraw() 38 | ch = '0' 39 | while ch not in fq.keys(): 40 | ch = simpledialog.askstring("MF/HF","ITU channel number") 41 | if (isinstance(ch,type(None))==True): 42 | exit(1) 43 | root.quit() 44 | 45 | # If X11 windows don't work, this cli can be used. 46 | #if len(sys.argv) < 2 : 47 | # print("Need a frequency argument") 48 | # exit(1) 49 | # 50 | #ch = sys.argv[1] 51 | #print("Selecting channel : ",ch) 52 | # 53 | #if ch not in fq.keys(): 54 | # print("Not a defined channel number") 55 | # exit(1) 56 | 57 | 58 | print("Setting RX VFOA to",int(int(fq[ch]['rx'])/1000),"kHz") 59 | print("Setting TX VFOB to",int(int(fq[ch]['tx'])/1000),"kHz") 60 | 61 | 62 | # Maritime channels are USB 63 | cmd = "rigctl -m 4 M USB 2700"; os.system(cmd) 64 | cmd = "rigctl -m 4 X USB 2700"; os.system(cmd) 65 | cmd = "rigctl -m 4 S 1 'VFOA'"; os.system(cmd) 66 | cmd = "rigctl -m 4 V 'VFOA'"; os.system(cmd) 67 | cmd = "rigctl -m 4 F "+fq[ch]['rx']; os.system(cmd) 68 | cmd = "rigctl -m 4 V 'VFOB'"; os.system(cmd); 69 | time.sleep(0.5) 70 | cmd = "rigctl -m 4 F "+fq[ch]['tx']; os.system(cmd) 71 | cmd = "rigctl -m 4 V 'VFOA'"; os.system(cmd) 72 | cmd = "rigctl -m 4 G 'TUNE'" ; #os.system(cmd) 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /G90/maritime-channels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/G90/maritime-channels.png -------------------------------------------------------------------------------- /GPSD Position and Time/chrony.conf.client: -------------------------------------------------------------------------------- 1 | # Welcome to the chrony configuration file. See chrony.conf(5) for more 2 | # information about usable directives. 3 | 4 | # Include configuration files found in /etc/chrony/conf.d. 5 | confdir /etc/chrony/conf.d 6 | 7 | # Openplotter have this addess. 8 | server 10.10.10.1 prefer iburst trust 9 | 10 | # Use Debian vendor zone if internet is available. 11 | #pool 2.debian.pool.ntp.org iburst 12 | 13 | # Use time sources from DHCP. 14 | sourcedir /run/chrony-dhcp 15 | 16 | # Use NTP sources found in /etc/chrony/sources.d. 17 | sourcedir /etc/chrony/sources.d 18 | 19 | # This directive specify the location of the file containing ID/key pairs for 20 | # NTP authentication. 21 | keyfile /etc/chrony/chrony.keys 22 | 23 | # This directive specify the file into which chronyd will store the rate 24 | # information. 25 | driftfile /var/lib/chrony/chrony.drift 26 | 27 | # Save NTS keys and cookies. 28 | ntsdumpdir /var/lib/chrony 29 | 30 | # Uncomment the following line to turn logging on. 31 | #log tracking measurements statistics 32 | 33 | # Log files location. 34 | logdir /var/log/chrony 35 | 36 | # Stop bad estimates upsetting machine clock. 37 | maxupdateskew 100.0 38 | 39 | # This directive enables kernel synchronisation (every 11 minutes) of the 40 | # real-time clock. Note that it can’t be used along with the 'rtcfile' directive. 41 | rtcsync 42 | 43 | # Step the system clock instead of slewing it if the adjustment is larger than 44 | # one second, on any (-1) clock updates. 45 | makestep 1 -1 46 | 47 | # Get TAI-UTC offset and leap seconds from the system tz database. 48 | # This directive must be commented out when using time sources serving 49 | # leap-smeared time. 50 | leapsectz right/UTC 51 | 52 | # Allow manual update (May 27, 2023 10:35:00) 53 | #manual on 54 | # 55 | 56 | 57 | -------------------------------------------------------------------------------- /GPSD Position and Time/chrony.conf.server: -------------------------------------------------------------------------------- 1 | # Welcome to the chrony configuration file. See chrony.conf(5) for more 2 | # information about usuable directives. 3 | #pool 2.debian.pool.ntp.org iburst 4 | 5 | # Local GPS / GPSD 6 | refclock SHM 0 offset 0.5 delay 0.1 refid GPS 7 | 8 | # This directive specify the location of the file containing ID/key pairs for 9 | # NTP authentication. 10 | keyfile /etc/chrony/chrony.keys 11 | 12 | # This directive specify the file into which chronyd will store the rate 13 | # information. 14 | driftfile /var/lib/chrony/chrony.drift 15 | 16 | # Uncomment the following line to turn logging on. 17 | #log tracking measurements statistics 18 | 19 | # Log files location. 20 | logdir /var/log/chrony 21 | 22 | # Stop bad estimates upsetting machine clock. 23 | maxupdateskew 100.0 24 | 25 | # This directive enables kernel synchronisation (every 11 minutes) of the 26 | # real-time clock. Note that it can’t be used along with the 'rtcfile' directive. 27 | rtcsync 28 | 29 | # Step the system clock instead of slewing it if the adjustment is larger than 30 | # one second, but only in the first 100 clock updates. 31 | makestep 1.0 100 32 | # 33 | 34 | # Allow all on network to sync 35 | allow 36 | 37 | # Allow manual update syntax like "May 27, 2023 10:35:00" 38 | manual 39 | 40 | 41 | -------------------------------------------------------------------------------- /GPSD Position and Time/get-date-from-SignalK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os, json, requests 3 | 4 | # Script to set the time and date from SignalK. The RPi have no internal 5 | # real time battery powered clock to keep time. Without internet 6 | # connection it cannot set its clock. When a separate GPS is not 7 | # connected it ned to ask the SignalK server for time data. 8 | 9 | # 10 | # Setting UTC timezone via CLI : 11 | # sudo rm /etc/localtime 12 | # sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime 13 | # 14 | # timedatectl list-timezones 15 | # 16 | # UTC or Europe/Oslo 17 | # 18 | # sudo timedatectl set-timezone Europe/Oslo 19 | # sudo timedatectl set-timezone UTC 20 | # 21 | 22 | resp = requests.get('http://demo.signalk.org/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 23 | 24 | #resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 25 | 26 | 27 | data = json.loads(resp.content) 28 | print(data) 29 | #cmd="sudo date -s "+data 30 | #os.system(cmd) 31 | Y=data[0:4] 32 | M=data[5:7] 33 | D=data[8:10] 34 | h=data[11:13] 35 | m=data[14:16] 36 | s=data[17:24] 37 | print(D,"/",M,"-",Y," ",h,":",m,":",s) 38 | 39 | -------------------------------------------------------------------------------- /GPSD Position and Time/gpsd: -------------------------------------------------------------------------------- 1 | # 2 | # This is the config file for gpsd loacted at: /etc/default/gpsd 3 | 4 | # Default settings for the gpsd init script and the hotplug wrapper. 5 | 6 | # Start the gpsd daemon automatically at boot time 7 | START_DAEMON="true" 8 | 9 | # Use USB hotplugging to add new USB devices automatically to the daemon 10 | USBAUTO="false" 11 | 12 | # Openplotter might use several deives, canbus interface will also 13 | # show up as ttyACM? , which sequence it not always predicable 14 | # However. Using udev rules can make symlinks to the correct devices. 15 | # Hence the USB GPS will show up as /dev/gps0 see: 16 | # https://github.com/olewsaa/Yacht-computer/tree/master/GPSD%20Position%20and%20Time 17 | # 18 | # 19 | # Devices gpsd should collect to at boot time. 20 | # They need to be read/writeable, either by user gpsd or the group dialout. 21 | DEVICES="/dev/gps0" 22 | 23 | # Other options you want to pass to gpsd 24 | GPSD_OPTIONS="-G -n" 25 | -------------------------------------------------------------------------------- /GPSD Position and Time/gpsd.cliclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Usage: 4 | # ./gpsd.cliclient.py 192.168.0.172 2947 5 | # ./gpsd.cliclient.py 6 | # Latter will use defaults set in the code below. 7 | # 8 | # Written by Ole W. Saastad 9 | # May 29. 2023 10 | # 11 | # 12 | import sys, gps 13 | 14 | host='192.168.0.172' 15 | port='2947' 16 | 17 | if len(sys.argv) == 2: 18 | host=sys.argv[1] 19 | elif len(sys.argv) > 2: 20 | host=sys.argv[1] 21 | port=sys.argv[2] 22 | 23 | #print(host,port) 24 | # Host and port is set directly : 25 | #session = gps.gps(mode=gps.WATCH_ENABLE,port='2947',host='192.168.0.172') 26 | 27 | session = gps.gps(mode=gps.WATCH_ENABLE, port=port, host=host) 28 | 29 | #print(session) 30 | for report in session: 31 | if report['class'] == 'TPV': 32 | print(report['lat'],report['lon']) 33 | lat=float(report['lat']) 34 | lon=float(report['lon']) 35 | if lon>0: 36 | l='E' 37 | else: 38 | l='W' 39 | print(format(lat,'9.5f')+' N',format(lon,'9.5f')+' '+l) 40 | print(format(int(lat),'03d')+'°', 41 | format((lat-int(lat))*60,'5.2f')+'\' N',) 42 | print(format(int(lon),'03d')+'°', 43 | format((lon-int(lon))*60,'5.2f')+'\'',l) 44 | 45 | break 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /GPSD Position and Time/gpsd.socket: -------------------------------------------------------------------------------- 1 | # 2 | # Located at : /lib/systemd/system/gpsd.socket 3 | [Unit] 4 | Description=GPS (Global Positioning System) Daemon Sockets 5 | 6 | [Socket] 7 | ListenStream=/var/run/gpsd.sock 8 | ListenStream=[::1]:2947 9 | #ListenStream=127.0.0.1:2947 10 | # Change to '0.0.0.0' to let all clients connect. 11 | ListenStream=0.0.0.0:2947 12 | SocketMode=0600 13 | 14 | [Install] 15 | WantedBy=sockets.target 16 | -------------------------------------------------------------------------------- /GPSD Position and Time/ntp.conf: -------------------------------------------------------------------------------- 1 | # /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help 2 | 3 | driftfile /var/lib/ntp/ntp.drift 4 | 5 | # Leap seconds definition provided by tzdata 6 | leapfile /usr/share/zoneinfo/leap-seconds.list 7 | 8 | # Specify one or more NTP servers. 9 | # 10 | # Local clock, this get updated from GPS/SignalK if no 11 | # internet. 12 | server 10.10.10.1 iburst 13 | fudge 10.10.10.1 stratum 8 14 | 15 | # From a pool, works only with an internet connection. 16 | ntp.justervesenet.no 17 | ntp.online.no 18 | ntp.uio.no 19 | pool 0.ubuntu.pool.ntp.org 20 | -------------------------------------------------------------------------------- /GPSD Position and Time/set-chrony-from-SignalK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os, json, requests 3 | 4 | # Script to set the time and date from SignalK. The RPi have no internal 5 | # real time battery powered clock to keep time. Without internet 6 | # connection it cannot set its clock. When a separate GPS is not 7 | # connected it ned to ask the SignalK server for time data. 8 | 9 | # 10 | # Setting UTC timezone via CLI : 11 | # sudo rm /etc/localtime 12 | # sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime 13 | # 14 | # timedatectl list-timezones 15 | # 16 | # UTC or Europe/Oslo 17 | # 18 | # sudo timedatectl set-timezone Europe/Oslo 19 | # sudo timedatectl set-timezone UTC 20 | # 21 | 22 | resp = requests.get('http://demo.signalk.org/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 23 | 24 | #resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 25 | 26 | 27 | data = json.loads(resp.content) 28 | print(data) 29 | #cmd="sudo date -s "+data 30 | #os.system(cmd) 31 | Y=data[0:4] 32 | M=data[5:7] 33 | D=data[8:10] 34 | h=data[11:13] 35 | m=data[14:16] 36 | s=data[17:24] 37 | #print(D,"/",M,"-",Y," ",h,":",m,":",s) 38 | # 39 | sec='{:.0f}'.format(float(s)) 40 | str=Y+"-"+M+"-"+D+"T"+h+":"+m+":"+'{:0>2}'.format(sec) 41 | cmd="sudo chronyc settime "+str 42 | print(cmd) 43 | #os.system(cmd) 44 | -------------------------------------------------------------------------------- /Gas-detector/MQ-sensors.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Gas alarm Arduino skectch. 4 | 5 | For Arduino NANO (Chineese make) 6 | Select Arduino NANO board 7 | Processor ATmega328P (old bootloader) 8 | 115200 baud 9 | 10 | */ 11 | 12 | int value; 13 | int Alarm=0; 14 | const int analog_ip0 = A0; // Naming analog input pin 15 | const int analog_ip1 = A1; // Naming analog input pin 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | // initialize digital pin 13 as an output. 20 | pinMode(13, OUTPUT); 21 | // initalize a pin for output 22 | // pinMode(); 23 | } 24 | 25 | void loop() { 26 | digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) 27 | delay(100); // wait n ms 28 | digitalWrite(13, LOW); // turn the LED off by making the voltage LOW 29 | delay(100); // wait n ms 30 | 31 | value = analogRead(analog_ip0); 32 | if (value>500) Alarm=1; 33 | //Serial.print("Detector value MQ2 :"); 34 | //Serial.print(value); 35 | 36 | value = analogRead(analog_ip1); 37 | if (value>500) Alarm=1; 38 | //Serial.print(" Detector value MQ9 :"); 39 | //Serial.print(value); 40 | //Serial.println(); 41 | if (Alarm>0) Serial.println("ALARM ALARM ALARM ALARM"); 42 | /* 43 | Insert code to set of some audio alarm, buzzer, bell or klaxon. 44 | */ 45 | } 46 | /* 47 | 48 | The Alarm will stay until the reset button or power off. 49 | Maybe add a reset button to the box. 50 | 51 | */ 52 | 53 | -------------------------------------------------------------------------------- /Gas-detector/README.md: -------------------------------------------------------------------------------- 1 | # Gas detector / monitor 2 | 3 | ## MQ gas sensors 4 | 5 | The MQ series of gas sensors is the backbone of this project. Spanning a range of gases these sensors can cover the most relevant gases one might to monitor onboard, Propane/Butane and Carbon Monoxide. 6 | 7 | An overview of sensors are given [here](https://www.mysensors.org/build/gas). From this list it's evident that MQ2 and MQ9 are the most relevent onboard, the web page also point to data sheets. MQ2 is sensitive to light hydrocarbons and smoke while MQ9 is sensitive to flameable gases and Carbon monoxide. 8 | 9 | The sketch provied is a test to start work with the sensors. It runs on a Nano board. It's in early development stage. 10 | -------------------------------------------------------------------------------- /IoToB/README.md: -------------------------------------------------------------------------------- 1 | # Internet of Things on Board 2 | 3 | Source code and documentaton related to the Internet of Things onboard 4 | (IoToB) and for the Yacht server project. 5 | 6 | The newest first, further down this text is older files and attempts. 7 | 8 | ## ESP-8266 modules 9 | 10 | The ESP-8266 module is remarkable litte device. With wifi built in and 11 | most of the software stack for this built in it has gained enormous 12 | popularity amoung makers. With a single core and limited memory the 13 | size of application it can run is limited. 14 | 15 | The breakout ESP‑12E board also known as 16 | [ESP‑12E](https://en.wikipedia.org/wiki/NodeMCU) is well suited on 17 | breadboard and on small circuit boards. It has a good selection of IO 18 | pins and a single Analog input with a 10 bit A/D. 19 | 20 | ## ESP-32 based modules 21 | 22 | ESP32-WROOM-32 The best known model of 23 | [ESP32](https://en.wikipedia.org/wiki/ESP32) is the 24 | [NodeMCU-ESP32S](https://docs.zerynth.com/latest/official/board.zerynth.nodemcu_esp32/docs/index.html). 25 | The ESP32 is a more versatile module with two cores, more memory and a 26 | lot more GPIO pins and a range of 12 bits ADCs built in. This together 27 | with the more powerfull 3.3V outlet makes it more suited to many 28 | Internet of things onboard (IoToB). The WiFiClient-U-and-I-SignalK in 29 | version 3 is a ESP-32 version. There are distinct differences in the 30 | handling of UDP trasactions. This prototype uses two ADS1115 for 31 | current measurements and the built in ADC for voltage measurement. 32 | 33 | ### Compare ESP8266 vs. ESP32 34 | There is a [nice page comparing](https://makeradvisor.com/esp32-vs-esp8266) the performance 35 | and other relevant characteristics of the two. 36 | The ESP32 suppport floating point, but performance is limited. This 37 | [blog](https://blog.classycode.com/esp32-floating-point-performance-6e9f6f567a69) entry 38 | show what to expect. 39 | 40 | 41 | ## Projects using the two modules 42 | 43 | ### Temperature 44 | WiFiClient-TempSignalK is a sketch where an ESP-8266 module is used to gather the temperatures from the one-wire bus and forward them to SignalK. It uses a simpler 8266 based ESP-12E module as this module is more than capable of performing this task. The 3.3V power converter have no problem feeding the DS18B20 sensors. 45 | 46 | ### Tank level 47 | Tank level monitoring by means of inductive sensors. Thes eon off sensors triggers IO pins on the ESP12 module and calculate a level number that is sent to SignalK over wifi. 48 | 49 | ### Current and voltage 50 | WiFiClient-U-and-I-SignalK.ino is a sketch where the ADS1115 is 51 | connected to the ESP-12E board. The Adafruit library for ADS1115 is 52 | used. GPIO pin 4 and 5 are connected to I2C SDA and SLC, this is the 53 | default. The ADS1115 measure current using Hall element sensors that 54 | provide +Vdd/2 at zero current and 0 voltage at maximum negative 55 | current and close to ful voltage at maximum positive current. Hence 56 | the differential mode. The ESP8266/12-E has a single analog input, 57 | this is used to measure the 12V voltage. Both current and voltage is 58 | then sent to the SignalK server. 59 | 60 | ### Voltage 61 | Initial test is to build a IoT voltmeter that accept 0-18 Volt and 62 | send a string of data to the SignalK server on the OpenPlotter 63 | computer. File is : WiFiClient-analog-SignalK.ino , this is rather 64 | simple sketch with not very elegant code. 65 | 66 | 67 | ### SignalK test 68 | The Python scripts are test scripts to send and receive data from the 69 | ESP8266 to check if things work correct and can be sent to SignalK. 70 | 71 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #Ignore thumbnails created by Windows 3 | Thumbs.db 4 | #Ignore files built by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | .vs/ 31 | #Nuget packages folder 32 | packages/ 33 | __vm/ 34 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/README.md: -------------------------------------------------------------------------------- 1 | # EspSoftwareSerial 2 | 3 | ## Implementation of the Arduino software serial library for the ESP8266 / ESP32 4 | 5 | This fork implements interrupt service routine best practice. 6 | In the receive interrupt, instead of blocking for whole bytes 7 | at a time - voiding any near-realtime behavior of the CPU - only level 8 | change and timestamp are recorded. The more time consuming phase 9 | detection and byte assembly are done in the main code. 10 | 11 | Except at high bitrates, depending on other ongoing activity, 12 | interrupts in particular, this software serial adapter 13 | supports full duplex receive and send. At high bitrates (115200bps) 14 | send bit timing can be improved at the expense of blocking concurrent 15 | full duplex receives, with the SoftwareSerial::enableIntTx(false) function call. 16 | 17 | The same functionality is given as the corresponding AVR library but 18 | several instances can be active at the same time. Speed up to 115200 baud 19 | is supported. Diverging from the AVR SoftwareSerial class, the constructor takes 20 | no arguments, instead the begin() function handles pin assignments and logic inversion. 21 | It also has optional input buffer capacity arguments for byte buffer and ISR bit buffer. 22 | This way, it is a better drop-in replacement for the hardware serial APIs on the ESP MCUs. 23 | 24 | Please note that due to the fact that the ESPs always have other activities 25 | ongoing, there will be some inexactness in interrupt timings. This may 26 | lead to inevitable, but few, bit errors when having heavy data traffic 27 | at high baud rates. 28 | 29 | 30 | ## Resource optimization 31 | 32 | The memory footprint can be optimized to just fit the amount of expected 33 | incoming asynchronous data. 34 | For this, the SoftwareSerial constructor provides two arguments. First, the 35 | octet buffer capacity for assembled received octets can be set. Read calls are 36 | satisfied from this buffer, freeing it in return. 37 | Second, the signal edge detection buffer of 32bit fields can be resized. 38 | One octet may require up to to 10 fields, but fewer may be needed, 39 | depending on the bit pattern. Any read or write calls check this buffer 40 | to assemble received octets, thus promoting completed octets to the octet 41 | buffer, freeing fields in the edge detection buffer. 42 | 43 | Look at the swsertest.ino example. There, on reset, ASCII characters ' ' to 'z' 44 | are send. This happens not as a block write, but in single write calls per 45 | character. As the example uses a local loopback wire, every outgoing bit is 46 | immediately received back. Therefore, any single write call causes up to 47 | 10 fields - depending on the exact bit pattern - to be occupied in the signal 48 | edge detection buffer. In turn, as explained before, each single write call 49 | also causes received bit assembly to be performed, promoting these bits from 50 | the signal edge detection buffer to the octet buffer as soon as possible. 51 | Explaining by way of contrast, if during a a single write call, perhaps because 52 | of using block writing, more than a single octet is received, there will be a 53 | need for more than 10 fields in the signal edge detection buffer. 54 | The necessary capacity of the octet buffer only depends on the amount of incoming 55 | data until the next read call. 56 | 57 | For the swsertest.ino example, this results in the following optimized 58 | constructor arguments to spend only the minimum RAM on buffers required: 59 | 60 | The octet buffer capacity (bufCapacity) is 93 (91 characters net plus two tolerance). 61 | The signal edge detection buffer capacity (isrBufCapacity) is 10, as each octet has 62 | 10 bits on the wire, which are immediately received during the write, and each 63 | write call causes the signal edge detection to promote the previously sent and 64 | received bits to the octet buffer. 65 | 66 | In a more generalized scenario, calculate the bits (use message size in octets 67 | times 10) that may be asynchronously received to determine the value for 68 | isrBufCapacity in the constructor. Also use the number of received octets 69 | that must be buffered for reading as the value of bufCapacity. 70 | The more frequently your code calls write or read functions, the greater the 71 | chances are that you can reduce the isrBufCapacity footprint without losing data, 72 | and each time you call read to fetch from the octet buffer, you reduce the 73 | need for space there. 74 | 75 | 76 | ## Using and updating EspSoftwareSerial in the esp8266com/esp8266 Arduino build environment 77 | 78 | The EspSoftwareSerial is both part of the BSP download for ESP8266 in Arduino, 79 | and it is set up as a Git submodule in the esp8266 source tree, 80 | specifically in .../esp8266/libraries/SoftwareSerial when using a Github 81 | repository clone in your Arduino sketchbook hardware directory. 82 | This supersedes any version of EspSoftwareSerial installed for instance via 83 | the Arduino library manager, it is not required to install EspSoftwareSerial 84 | for the ESP8266 separately at all. 85 | 86 | The responsible maintainer of the esp8266 repository has kindly shared the 87 | following command line instructions to use, if one wishes to manually 88 | update EspSoftwareSerial to a newer release than pulled in via the ESP8266 Arduino BSP: 89 | 90 | To update esp8266/arduino SoftwareSerial submodule to lastest master: 91 | 92 | ``` 93 | (optional, clean it:) 94 | $ rm -rf libraries/SoftwareSerial 95 | $ git submodule update --init 96 | (now update it:) 97 | $ cd libraries/SoftwareSerial 98 | $ git checkout master 99 | $ git pull 100 | ``` 101 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/UPDATE.md: -------------------------------------------------------------------------------- 1 | # Changes to the SoftwareSerial library 2 | 3 | ## Background 4 | 5 | The simple examples would not build using the following versions of 6 | the build invironment. 7 | 8 | - Arduino IDE 1.8.12 9 | - ESP8266 library 2.7.1 10 | 11 | 12 | ## Fix a building issue 13 | 14 | The SoftwareSerial library with 9 bit support failed to build applications 15 | with the current setup. 16 | 17 | One line needed to be changed in the file EspSoftwareSerial/src/SoftwareSerial.cpp : 18 | * //attachInterruptArg(digitalPinToInterrupt(m_rxPin), (void (*)())(rxBitISR), this, CHANGE); 19 | * Attachinterruptarg(digitalPinToInterrupt(m_rxPin), reinterpret_cast(rxBitISR), this, CHANGE); 20 | 21 | An error in the casting of void function and void parameters. Using the 22 | same line from the initial 8 bit version worked. 23 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/examples/onewiretest/onewiretest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "SoftwareSerial.h" 3 | 4 | SoftwareSerial swSer1; 5 | SoftwareSerial swSer2; 6 | 7 | void setup() { 8 | delay(2000); 9 | Serial.begin(115200); 10 | Serial.println("\nOne Wire Half Duplex Serial Tester"); 11 | swSer1.begin(115200, 12, 12, SWSERIAL_8N1, false, 256); 12 | swSer1.enableIntTx(true); 13 | swSer2.begin(115200, 14, 14, SWSERIAL_8N1, false, 256); 14 | swSer2.enableIntTx(true); 15 | } 16 | 17 | void loop() { 18 | Serial.println("\n\nTesting on swSer1"); 19 | Serial.print("Enter something to send using swSer1."); 20 | checkSwSerial(&swSer1); 21 | 22 | Serial.println("\n\nTesting on swSer2"); 23 | Serial.print("Enter something to send using swSer2."); 24 | checkSwSerial(&swSer2); 25 | 26 | } 27 | 28 | void checkSwSerial(SoftwareSerial* ss) { 29 | byte ch; 30 | while (!Serial.available()); 31 | ss->enableTx(true); 32 | while (Serial.available()) { 33 | ch = Serial.read(); 34 | ss->write(ch); 35 | } 36 | ss->enableTx(false); 37 | // wait 1 second for the reply from SOftwareSerial if any 38 | delay(1000); 39 | if (ss->available()) { 40 | Serial.print("\nResult:"); 41 | while (ss->available()) { 42 | ch = (byte)ss->read(); 43 | Serial.print(ch < 0x01 ? " 0" : " "); 44 | Serial.print(ch, HEX); 45 | } 46 | Serial.println(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/examples/repeater/repeater.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // On ESP8266: 4 | // SoftwareSerial loopback for remote source (loopback.ino), or hardware loopback. 5 | // Connect source D5 (rx) to local D8 (tx), source D6 (tx) to local D7 (rx). 6 | // Hint: The logger is run at 9600bps such that enableIntTx(true) can remain unchanged. Blocking 7 | // interrupts severely impacts the ability of the SoftwareSerial devices to operate concurrently 8 | // and/or in duplex mode. 9 | // On ESP32: 10 | // For software or hardware loopback, connect source rx to local D8 (tx), source tx to local D7 (rx). 11 | 12 | #if !defined(D5) 13 | #define D5 (14) 14 | #define D6 (12) 15 | #define D7 (13) 16 | #define D8 (15) 17 | #endif 18 | 19 | //#define HWLOOPBACK 1 20 | //#define HALFDUPLEX 1 21 | 22 | #ifdef ESP32 23 | constexpr int IUTBITRATE = 19200; 24 | #else 25 | constexpr int IUTBITRATE = 19200; 26 | #endif 27 | 28 | constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8N1; 29 | 30 | constexpr int BLOCKSIZE = 16; // use fractions of 256 31 | 32 | 33 | unsigned long start; 34 | String bitRateTxt("Effective data rate: "); 35 | int rxCount; 36 | int seqErrors; 37 | int expected; 38 | constexpr int ReportInterval = IUTBITRATE / 8; 39 | 40 | #ifdef HWLOOPBACK 41 | #if defined(ESP8266) 42 | HardwareSerial& repeater(Serial); 43 | SoftwareSerial logger; 44 | #elif defined(ESP32) 45 | HardwareSerial& repeater(Serial2); 46 | HardwareSerial& logger(Serial); 47 | #endif 48 | #else 49 | SoftwareSerial repeater; 50 | HardwareSerial& logger(Serial); 51 | #endif 52 | 53 | void setup() { 54 | #ifdef HWLOOPBACK 55 | #if defined(ESP8266) 56 | repeater.begin(IUTBITRATE); 57 | repeater.setRxBufferSize(2 * BLOCKSIZE); 58 | repeater.swap(); 59 | logger.begin(9600, RX, TX); 60 | #elif defined(ESP32) 61 | repeater.begin(IUTBITRATE, SERIAL_8N1, D7, D8); 62 | repeater.setRxBufferSize(2 * BLOCKSIZE); 63 | logger.begin(9600); 64 | #endif 65 | #else 66 | #if defined(ESP8266) 67 | repeater.begin(IUTBITRATE, D7, D8, swSerialConfig, false, 2 * BLOCKSIZE); 68 | #elif defined(ESP32) 69 | repeater.begin(IUTBITRATE, D7, D8, swSerialConfig, false, 2 * BLOCKSIZE); 70 | #endif 71 | #ifdef HALFDUPLEX 72 | repeater.enableIntTx(false); 73 | #endif 74 | Serial.begin(9600); 75 | #endif 76 | 77 | start = micros(); 78 | rxCount = 0; 79 | seqErrors = 0; 80 | } 81 | 82 | void loop() { 83 | #ifdef HALFDUPLEX 84 | unsigned char block[BLOCKSIZE]; 85 | #endif 86 | int inCnt = 0; 87 | // starting deadline for the first bytes to come in 88 | uint32_t deadline = micros() + 200000; 89 | while (static_cast(deadline - micros()) > 0) { 90 | if (0 >= repeater.available()) { 91 | delay(1); 92 | continue; 93 | } 94 | int r = repeater.read(); 95 | if (r == -1) { logger.println("read() == -1"); } 96 | if (expected == -1) { expected = r; } 97 | else { 98 | expected = (expected + 1) % 256; 99 | } 100 | if (r != (expected & ((1 << (5 + swSerialConfig % 4)) - 1))) { 101 | ++seqErrors; 102 | expected = -1; 103 | } 104 | ++rxCount; 105 | #ifdef HALFDUPLEX 106 | block[inCnt] = r; 107 | #else 108 | repeater.write(r); 109 | #endif 110 | if (++inCnt >= BLOCKSIZE) { break; } 111 | // wait for more outstanding bytes to trickle in 112 | deadline = micros() + static_cast(1000000 * 10 * BLOCKSIZE / IUTBITRATE * 32); 113 | } 114 | 115 | #ifdef HALFDUPLEX 116 | repeater.write(block, inCnt); 117 | #endif 118 | 119 | if (inCnt != 0 && inCnt != BLOCKSIZE) { 120 | logger.print("Got "); logger.print(inCnt); logger.println(" bytes during buffer interval"); 121 | } 122 | 123 | if (rxCount >= ReportInterval) { 124 | auto end = micros(); 125 | unsigned long interval = end - start; 126 | long cps = rxCount * (1000000.0 / interval); 127 | long seqErrorsps = seqErrors * (1000000.0 / interval); 128 | logger.println(bitRateTxt + 10 * cps + "bps, " 129 | + seqErrorsps + "cps seq. errors (" + 100.0 * seqErrors / rxCount + "%)"); 130 | start = end; 131 | rxCount = 0; 132 | seqErrors = 0; 133 | expected = -1; 134 | } 135 | } -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/examples/servoTester/servoTester.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | SoftwareSerial swSer; 5 | 6 | byte buf[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED }; 7 | byte cmd[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED }; 8 | byte ver[10] = { 0xFC, 0xCF,0x00,0xAA,0x41, 0x16, 0x51, 0x01, 0x00, 0xED }; 9 | 10 | 11 | void setup() { 12 | delay(2000); 13 | Serial.begin(115200); 14 | Serial.println("\nAlpha 1S Servo Tester"); 15 | swSer.begin(115200, 12, 12, SWSERIAL_8N1, false, 256); 16 | } 17 | 18 | void loop() { 19 | for (int i = 1; i <= 32; i++) { 20 | GetVersion(i); 21 | delay(100); 22 | } 23 | SetLED(1, 0); 24 | GoPos(1, 0, 50); 25 | delay(1000); 26 | GoPos(1, 90, 50); 27 | delay(1000); 28 | GoPos(1, 100, 50); 29 | delay(1000); 30 | SetLED(1, 1); 31 | delay(2000); 32 | } 33 | 34 | 35 | 36 | 37 | void GetVersion(byte id) { 38 | memcpy(buf, cmd, 10); 39 | buf[0] = 0xFC; 40 | buf[1] = 0xCF; 41 | buf[2] = id; 42 | buf[3] = 0x01; 43 | SendCommand(); 44 | } 45 | 46 | 47 | void GoPos(byte id, byte Pos, byte Time) { 48 | memcpy(buf, cmd, 10); 49 | buf[2] = id; 50 | buf[3] = 0x01; 51 | buf[4] = Pos; 52 | buf[5] = Time; 53 | buf[6] = 0x00; 54 | buf[7] = Time; 55 | SendCommand(); 56 | } 57 | 58 | void GetPos(byte id) { 59 | memcpy(buf, cmd, 10); 60 | buf[2] = id; 61 | buf[3] = 0x02; 62 | SendCommand(); 63 | } 64 | 65 | 66 | void SetLED(byte id, byte mode) { 67 | memcpy(buf, cmd, 10); 68 | buf[2] = id; 69 | buf[3] = 0x04; 70 | buf[4] = mode; 71 | SendCommand(); 72 | } 73 | 74 | void SendCommand() { 75 | SendCommand(true); 76 | } 77 | 78 | void SendCommand(bool checkResult) { 79 | byte sum = 0; 80 | for (int i = 2; i < 8; i++) { 81 | sum += buf[i]; 82 | } 83 | buf[8] = sum; 84 | ShowCommand(); 85 | swSer.flush(); 86 | swSer.enableTx(true); 87 | swSer.write(buf, 10); 88 | swSer.enableTx(false); 89 | if (checkResult) checkReturn(); 90 | } 91 | 92 | void ShowCommand() { 93 | Serial.print(millis()); 94 | Serial.print(" OUT>>"); 95 | for (int i = 0; i < 10; i++) { 96 | Serial.print((buf[i] < 0x10 ? " 0" : " ")); 97 | Serial.print(buf[i], HEX); 98 | } 99 | Serial.println(); 100 | } 101 | 102 | void checkReturn() { 103 | unsigned long startMs = millis(); 104 | while (((millis() - startMs) < 500) && (!swSer.available())); 105 | if (swSer.available()) { 106 | Serial.print(millis()); 107 | Serial.print(" IN>>>"); 108 | while (swSer.available()) { 109 | byte ch = (byte)swSer.read(); 110 | Serial.print((ch < 0x10 ? " 0" : " ")); 111 | Serial.print(ch, HEX); 112 | } 113 | Serial.println(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/examples/swsertest/swsertest.ino: -------------------------------------------------------------------------------- 1 | // On ESP8266: 2 | // At 80MHz runs up 57600ps, and at 160MHz CPU frequency up to 115200bps with only negligible errors. 3 | // Connect pin 12 to 14. 4 | 5 | #include 6 | 7 | #if !defined(D5) 8 | #define D5 (14) 9 | #define D6 (12) 10 | #define D7 (13) 11 | #define D8 (15) 12 | #endif 13 | 14 | #ifdef ESP32 15 | #define BAUD_RATE 57600 16 | #else 17 | #define BAUD_RATE 57600 18 | #endif 19 | 20 | // Reminder: the buffer size optimizations here, in particular the isrBufSize that only accommodates 21 | // a single 8N1 word, are on the basis that any char written to the loopback SoftwareSerial adapter gets read 22 | // before another write is performed. Block writes with a size greater than 1 would usually fail. 23 | SoftwareSerial swSer; 24 | 25 | void setup() { 26 | Serial.begin(115200); 27 | swSer.begin(BAUD_RATE, D5, D6, SWSERIAL_8N1, false, 95, 11); 28 | 29 | Serial.println("\nSoftware serial test started"); 30 | 31 | for (char ch = ' '; ch <= 'z'; ch++) { 32 | swSer.write(ch); 33 | } 34 | swSer.println(""); 35 | } 36 | 37 | void loop() { 38 | while (swSer.available() > 0) { 39 | Serial.write(swSer.read()); 40 | yield(); 41 | } 42 | while (Serial.available() > 0) { 43 | swSer.write(Serial.read()); 44 | yield(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for SoftwareSerial 3 | # (esp8266) 4 | ####################################### 5 | 6 | ####################################### 7 | # Datatypes (KEYWORD1) 8 | ####################################### 9 | 10 | SoftwareSerial KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | begin KEYWORD2 17 | baudRate KEYWORD2 18 | setTransmitEnablePin KEYWORD2 19 | enableIntTx KEYWORD2 20 | overflow KEYWORD2 21 | available KEYWORD2 22 | peek KEYWORD2 23 | read KEYWORD2 24 | flush KEYWORD2 25 | write KEYWORD2 26 | enableRx KEYWORD2 27 | enableTx KEYWORD2 28 | listen KEYWORD2 29 | end KEYWORD2 30 | isListening KEYWORD2 31 | stopListening KEYWORD2 32 | onReceive KEYWORD2 33 | perform_work KEYWORD2 34 | 35 | ####################################### 36 | # Constants (LITERAL1) 37 | ####################################### 38 | 39 | SW_SERIAL_UNUSED_PIN LITERAL1 40 | SWSERIAL_5N1 LITERAL1 41 | SWSERIAL_6N1 LITERAL1 42 | SWSERIAL_7N1 LITERAL1 43 | SWSERIAL_8N1 LITERAL1 44 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EspSoftwareSerial", 3 | "version": "5.3.4", 4 | "keywords": [ 5 | "serial", "io", "softwareserial" 6 | ], 7 | "description": "Implementation of the Arduino software serial for ESP8266/ESP32.", 8 | "repository": 9 | { 10 | "type": "git", 11 | "url": "https://github.com/plerup/espsoftwareserial" 12 | }, 13 | "frameworks": "arduino", 14 | "platforms": "*" 15 | } 16 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/library.properties: -------------------------------------------------------------------------------- 1 | name=EspSoftwareSerial 2 | version=5.3.4 3 | author=Peter Lerup, Dirk Kaar 4 | maintainer=Peter Lerup 5 | sentence=Implementation of the Arduino software serial for ESP8266/ESP32. 6 | paragraph= 7 | category=Signal Input/Output 8 | url=https://github.com/plerup/espsoftwareserial/ 9 | architectures=esp8266,esp32 10 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/src/SoftwareSerial.h: -------------------------------------------------------------------------------- 1 | /* 2 | SoftwareSerial.h 3 | 4 | SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266/ESP32. 5 | Copyright (c) 2015-2016 Peter Lerup. All rights reserved. 6 | Copyright (c) 2018-2019 Dirk O. Kaar. All rights reserved. 7 | 8 | This library is free software; you can redistribute it and/or 9 | modify it under the terms of the GNU Lesser General Public 10 | License as published by the Free Software Foundation; either 11 | version 2.1 of the License, or (at your option) any later version. 12 | 13 | This library is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public 19 | License along with this library; if not, write to the Free Software 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | */ 23 | 24 | #ifndef __SoftwareSerial_h 25 | #define __SoftwareSerial_h 26 | 27 | #include "circular_queue/circular_queue.h" 28 | #include 29 | #include 30 | 31 | /// If only one tx or rx wanted then use this as parameter for the unused pin. 32 | constexpr int SW_SERIAL_UNUSED_PIN = -1; 33 | 34 | enum SoftwareSerialConfig { 35 | SWSERIAL_5N1 = 0, 36 | SWSERIAL_6N1, 37 | SWSERIAL_7N1, 38 | SWSERIAL_8N1, 39 | SWSERIAL_9N1, 40 | }; 41 | 42 | /// This class is compatible with the corresponding AVR one, however, 43 | /// the constructor takes no arguments, for compatibility with the 44 | /// HardwareSerial class. 45 | /// Instead, the begin() function handles pin assignments and logic inversion. 46 | /// It also has optional input buffer capacity arguments for byte buffer and ISR bit buffer. 47 | /// Bitrates up to at least 115200 can be used. 48 | class SoftwareSerial { 49 | public: 50 | SoftwareSerial(); 51 | SoftwareSerial(const SoftwareSerial&) = delete; 52 | SoftwareSerial& operator= (const SoftwareSerial&) = delete; 53 | virtual ~SoftwareSerial(); 54 | void begin(uint32_t baud, int8_t rxPin, int8_t txPin = -1, 55 | SoftwareSerialConfig config = SWSERIAL_8N1, 56 | bool invert = false, int bufCapacity = 64, int isrBufCapacity = 0); 57 | uint32_t baudRate(); 58 | /// Transmit control pin. 59 | void setTransmitEnablePin(int8_t txEnablePin); 60 | /// Enable or disable interrupts during tx. 61 | void enableIntTx(bool on); 62 | 63 | bool overflow(); 64 | 65 | int available() ; 66 | int availableForWrite() { 67 | if (!m_txValid) return 0; 68 | return 1; 69 | } 70 | int peek() ; 71 | int read() ; 72 | /// The readBytes functions are non-waiting, there is no timeout. 73 | size_t readBytes(uint16_t* buffer, size_t size) ; 74 | /// The readBytes functions are non-waiting, there is no timeout. 75 | size_t readBytes(char* buffer, size_t size) { 76 | return readBytes(reinterpret_cast(buffer), size); 77 | } 78 | void flush() ; 79 | size_t write(uint16_t byte) ; 80 | size_t write(const uint16_t* buffer, size_t size) ; 81 | // size_t write(const char* buffer, size_t size) { 82 | // return write(reinterpret_cast(buffer), size); 83 | // } 84 | operator bool() const { return m_rxValid || m_txValid; } 85 | 86 | /// Disable or enable interrupts on the rx pin. 87 | void enableRx(bool on); 88 | /// One wire control. 89 | void enableTx(bool on); 90 | 91 | // AVR compatibility methods. 92 | bool listen() { enableRx(true); return true; } 93 | void end(); 94 | bool isListening() { return m_rxEnabled; } 95 | bool stopListening() { enableRx(false); return true; } 96 | 97 | /// Set an event handler for received data. 98 | void onReceive(std::function handler); 99 | 100 | /// Run the internal processing and event engine. Can be iteratively called 101 | /// from loop, or otherwise scheduled. 102 | void perform_work(); 103 | 104 | // using Print::write; 105 | 106 | private: 107 | // If asyn, it's legal to exceed the deadline, for instance, 108 | // by enabling interrupts. 109 | void preciseDelay(bool asyn, uint32_t savedPS); 110 | // If withStopBit is set, either cycle contains a stop bit. 111 | // If dutyCycle == 0, the level is not forced to HIGH. 112 | // If offCycle == 0, the level remains unchanged from dutyCycle. 113 | void writePeriod( 114 | uint32_t dutyCycle, uint32_t offCycle, bool withStopBit, uint32_t savedPS); 115 | bool isValidGPIOpin(int8_t pin); 116 | /* check m_rxValid that calling is safe */ 117 | void rxBits(); 118 | void rxBits(const uint32_t& isrCycle); 119 | 120 | static void rxBitISR(SoftwareSerial* self); 121 | 122 | // Member variables 123 | bool m_oneWire; 124 | int8_t m_rxPin = SW_SERIAL_UNUSED_PIN; 125 | int8_t m_txPin = SW_SERIAL_UNUSED_PIN; 126 | int8_t m_txEnablePin = SW_SERIAL_UNUSED_PIN; 127 | bool m_rxValid = false; 128 | bool m_rxEnabled = false; 129 | bool m_txValid = false; 130 | bool m_txEnableValid = false; 131 | bool m_invert; 132 | bool m_overflow = false; 133 | uint8_t m_dataBits; // How many bits are in the data frame? See: SoftwareSerialConfig. 134 | uint32_t m_bit_us; 135 | uint32_t m_bitCycles; 136 | uint32_t m_periodStart; 137 | uint32_t m_periodDuration; 138 | bool m_intTxEnabled; 139 | std::unique_ptr > m_buffer; 140 | // the ISR stores the relative bit times in the buffer. The inversion corrected level is used as sign bit (2's complement): 141 | // 1 = positive including 0, 0 = negative. 142 | std::unique_ptr > m_isrBuffer; 143 | std::atomic m_isrOverflow; 144 | uint32_t m_isrLastCycle; 145 | int16_t m_rxCurBit; // Some kind of counter? // 0 - 7: data bits. -1: start bit. 8: stop bit. 146 | uint16_t m_rxCurByte = 0; 147 | 148 | std::function receiveHandler; 149 | }; 150 | 151 | #endif // __SoftwareSerial_h 152 | -------------------------------------------------------------------------------- /IoToB/Seatalk/EspSoftwareSerial-9bit-modified/src/circular_queue/ghostl.h: -------------------------------------------------------------------------------- 1 | /* 2 | ghostl.h - Implementation of a bare-bones, mostly no-op, C++ STL shell 3 | that allows building some Arduino ESP8266/ESP32 4 | libraries on Aruduino AVR. 5 | Copyright (c) 2019 Dirk O. Kaar. All rights reserved. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | #ifndef __ghostl_h 23 | #define __ghostl_h 24 | 25 | #if defined(ARDUINO_ARCH_SAMD) 26 | #include 27 | #endif 28 | 29 | namespace std 30 | { 31 | #if !defined(ARDUINO_ARCH_SAMD) 32 | typedef enum memory_order { 33 | memory_order_relaxed, 34 | memory_order_acquire, 35 | memory_order_release, 36 | memory_order_seq_cst 37 | } memory_order; 38 | template< typename T > class atomic { 39 | private: 40 | T value; 41 | public: 42 | atomic() {} 43 | atomic(T desired) { value = desired; } 44 | void store(T desired, std::memory_order = std::memory_order_seq_cst) volatile noexcept { value = desired; } 45 | T load(std::memory_order = std::memory_order_seq_cst) const volatile noexcept { return value; } 46 | }; 47 | inline void atomic_thread_fence(std::memory_order order) noexcept {} 48 | template< typename T > T&& move(T& t) noexcept { return static_cast(t); } 49 | #endif 50 | 51 | template< typename T, unsigned long N > struct array 52 | { 53 | T _M_elems[N]; 54 | unsigned long size() const { return N; } 55 | T& operator[](unsigned long i) { return _M_elems[i]; } 56 | const T& operator[](unsigned long i) const { return _M_elems[i]; } 57 | }; 58 | 59 | template< typename T > class unique_ptr 60 | { 61 | public: 62 | using pointer = T*; 63 | unique_ptr() noexcept : ptr(nullptr) {} 64 | unique_ptr(pointer p) : ptr(p) {} 65 | pointer operator->() const noexcept { return ptr; } 66 | T& operator[](size_t i) const { return ptr[i]; } 67 | void reset(pointer p = pointer()) noexcept 68 | { 69 | delete ptr; 70 | ptr = p; 71 | } 72 | T& operator*() const { return *ptr; } 73 | private: 74 | pointer ptr; 75 | }; 76 | 77 | template< typename T > using function = T*; 78 | } 79 | 80 | #endif // __ghostl_h 81 | -------------------------------------------------------------------------------- /IoToB/Seatalk/README.md: -------------------------------------------------------------------------------- 1 | # Yacht-computer project 2 | 3 | ## Now supported using SignalK 4 | The the recent support using SignalK the need to writing a Seatalk-1 to wifi becomes less interesting. 5 | The project is currently paused. 6 | https://sites.google.com/site/olewsaa/yacht-server-with-raspberry/compass-server 7 | 8 | 9 | ## Raymarine Seatalk 1 to SignalK over Wifi 10 | 11 | ### Introduction 12 | Seatalk data are sendt over a special single wire propriatary bus and 13 | in a special Seatalk format. The electrical signalling is using 12V and null Volt. 14 | This need to be translated to the TTL 3.3V level for the ESP8266 to read. 15 | The Seatalk messages need to be read (in 9 bit format) and decoded. The decoded data 16 | are then transmitted over Wifi to the SignalK server and displayed by any SignalK 17 | web application. 18 | 19 | ### ESP8266 are well suited 20 | The ESP8266 are well suited to this work, it handle wifi comunication well and 21 | can be programmed to use pins to look like a serial port and have enough 22 | processor capacity to read and decode the messages. 23 | 24 | The ESP8266 are also easy to program with full support in the well known 25 | Arduiono IDE. 26 | 27 | 28 | ### ESP8266 Serial ports 29 | The ESP8266 only have one serial port and this is the connection, upload 30 | and debug port. In order to get an extra port a software port is neeed. 31 | This is a standard library to eh arduino IDE, SoftwareSerial. This can 32 | only handle 8 bits serial data. Since Seatalk uses 9 bot data values a 33 | forked and modified library is used. Some issues were encountured, hence 34 | a replacement file is made available. 35 | 36 | The test for library and software is called SoftwareSerialTest.ino and is 37 | a simple script adapted from the examples to test the software serial port. 38 | 39 | The naming of the ports for D5 and D6 are the same marking as in the 40 | board. The 14 and 12 refer to the GPIO ports. The first pin argument is the Rx 41 | and the second the Tx. Hence the call: 42 | swSer.begin(BAUDRATE, D5, D6, SWSERIAL_9N1, false, 95, 11); 43 | would set up D5 (GPIO 14) as the receive pin and D6 (GPIO 12) as the transmit pin. 44 | 45 | The repo for the 9 bit library is found here: 46 | https://github.com/ionini/espsoftwareserial 47 | 48 | Some adaptation are neeed, and information about this is found in the file UPDATE.md 49 | within my version of the SoftwareSerial directory. In addtion a working copy of the 50 | SoftwareSerial 9bit files. 51 | 52 | 53 | ### Convert from 12V seatalk signaling to ESP8266 3.3V signaling 54 | 55 | The Seatalk uses 0V as logic 1 and +12V as logic 0, while the ESP8266 uses 56 | 0V for logic 0 and 3.3V for logic 1. A simple inverting and level converter using 57 | a single transistor set up needed. The drawing is available in the file 58 | Seatalk-to-ESP8266_schem.png . 59 | 60 | 61 | ### Decoding the Seatalk messages 62 | 63 | The Raymarine Seatalk protocol are not published and not available to the public. 64 | However, Thomas Knauf have done the reverse engineering and published a good 65 | description at his web site : http://www.thomasknauf.de/seatalk.htm . 66 | The page http://www.thomasknauf.de/rap/seatalk2.htm go through the different 67 | types of messages and their words (9-bit), bytes and nibbles needed to be 68 | read and handled. Some other projects provide valuable input : 69 | http://berreizeta.blogspot.com/2016/12/blog-post.html and the software at the 70 | google drive : https://drive.google.com/open?id=0B-aQ4eIWtpZcV3pMRTYyV2FpY1U . 71 | 72 | 73 | -------------------------------------------------------------------------------- /IoToB/Seatalk/Seatalk-Grapher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/IoToB/Seatalk/Seatalk-Grapher.png -------------------------------------------------------------------------------- /IoToB/Seatalk/Seatalk-to-ESP8266_schem.md: -------------------------------------------------------------------------------- 1 | # Yacht-computer project 2 | 3 | ## Raymarine Seatalk 1 to SignalK over Wifi 4 | 5 | ### Electric interface 6 | 7 | The Seatalk uses a different signal level coding than the serial 8 | communication fo the normal Arduino/ESP8266, +12V and 0V. The common 9 | TTL serial signal level are 0V for logic 0 and +5V or 3.3V for 10 | logic 1. See the the [Thomas Knauf Seatalk 11 | page](http://www.thomasknauf.de/rap/seatalk1.htm) which is the reference 12 | page for Seatalk information. This require a level convertion from 13 | +12V to +3.3V in order to process the signal using the 14 | ESP8222 which uses uses 3.3V (Arduino uses 5V). 15 | 16 | #### Simulation 17 | 18 | The figure show how the level convertion is done using a single none 19 | inverting transistor stage, the simulation show the voltage levels and 20 | that the output is safe to output to the pins of the ESP8622. The 21 | Seatalk data source is replaced by a signal generator to simulate the 22 | Seatalk data. 23 | 24 | ![figure](https://github.com/olewsaa/Yacht-computer/blob/master/IoToB/Seatalk/Seatalk-to-ESP8266_schem.png) 25 | 26 | And the electric signal simulated to show the 3.3V signaling level. 27 | 28 | ![figure](https://github.com/olewsaa/Yacht-computer/blob/master/IoToB/Seatalk/Seatalk-Grapher.png) 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /IoToB/Seatalk/Seatalk-to-ESP8266_schem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/IoToB/Seatalk/Seatalk-to-ESP8266_schem.png -------------------------------------------------------------------------------- /IoToB/Seatalk/SoftwareSerialTest.ino: -------------------------------------------------------------------------------- 1 | // On ESP8266: 2 | // At 80MHz runs up 57600ps, and at 160MHz CPU frequency up to 115200bps with only negligible errors. 3 | // Connect pin 12 to 14. 4 | 5 | /* 6 | * Test for SoftwareSerial (to get en extra serial port on the ESP8266. 7 | * This example is part if initial testing using a SoftwareSerial 9 bit implementation. 8 | * https://github.com/ionini/espsoftwareserial Downloaded and installed as under : ~/Arduino/libraries 9 | * EspSoftwareSerial -> EspSoftwareSerial-9bit/ 10 | * EspSoftwareSerial-9bit 11 | * EspSoftwareSerial-orig 12 | * 13 | * An additional change needed to be applied in the file EspSoftwareSerial/src/SoftwareSerial.cpp : 14 | * //attachInterruptArg(digitalPinToInterrupt(m_rxPin), (void (*)())(rxBitISR), this, CHANGE); 15 | * attachInterruptArg(digitalPinToInterrupt(m_rxPin), reinterpret_cast(rxBitISR), this, CHANGE); 16 | * 17 | * An error in the casting of void function and viod parameters. Using the same line from the initial 18 | * 8 bit version worked. 19 | * 20 | * The calling sequence is different in the original 8 bit versions and the extened 9 bit version. 21 | * The 9 bit version looks like this: 22 | * swSer.begin(BAUD_RATE, D5, D6, SWSERIAL_9N1, false, 95, 11); 23 | * Pin paramaters BEFORE the world lenght, parity and stop bits. 24 | * 25 | * This testing is initial work in order to read 9-bit data from the Raymarine Seatalk data. 26 | * 27 | */ 28 | 29 | 30 | 31 | #include 32 | 33 | #if defined(ESP8266) && !defined(D5) 34 | #define D5 (14) // D5 is the D5 pin on the board, also named GPIO 14, hence (14) which reflects the GPIO14 35 | #define D6 (12) // D6 is the D6 pin on the board, also named GPIO 12, hence (12) which reflects the GPIO12 36 | #define D7 (13) 37 | #define D8 (15) 38 | #endif 39 | 40 | #ifdef ESP32 41 | #define BAUD_RATE 57600 42 | #else 43 | #define BAUD_RATE 4800 44 | #endif 45 | 46 | // Reminder: the buffer size optimizations here, in particular the isrBufSize that only accommodates 47 | // a single 8N1 word, are on the basis that any char written to the loopback SoftwareSerial adapter gets read 48 | // before another write is performed. Block writes with a size greater than 1 would usually fail. 49 | SoftwareSerial swSer; 50 | 51 | void setup() { 52 | Serial.begin(115200); 53 | swSer.begin(BAUD_RATE, D5, D6, SWSERIAL_9N1, false, 95, 11); 54 | 55 | Serial.println("\nSoftware serial test started"); 56 | 57 | for (char ch = ' '; ch <= 'z'; ch++) { 58 | swSer.write(ch); 59 | Serial.write(ch); 60 | } 61 | swSer.write(makeWord(' ','\n')); 62 | Serial.println("\nData written to SoftwareSerial port"); 63 | } 64 | 65 | 66 | void loop() { 67 | while (swSer.available() > 0) { 68 | unsigned int d; 69 | //Serial.write(swSer.peek()); 70 | d=swSer.read(); 71 | Serial.write(d); 72 | // Serial.write(swSer.read()); 73 | yield(); 74 | } 75 | while (Serial.available() > 0) { 76 | swSer.write(Serial.read()); 77 | yield(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /IoToB/Tank-level/README.md: -------------------------------------------------------------------------------- 1 | # Tank level sensors 2 | 3 | ## ESP-8266 breadboard layout 4 | 5 | I have used an ESP-12E NodeMCU 1.0 board from China for this 6 | project. The software development environment is Arduino IDE which 7 | relies on the (close enough) C programming language. 8 | 9 | The tank level has 10 | [web pages](https://sites.google.com/site/olewsaa/yacht-server-with-raspberry/tank-level-monitor) 11 | about the project with overview of the project and pictures, given here are source code and 12 | breadboad schematics. 13 | The breadboard picture show the connections to where the NPN inductive 14 | sensors are connected. I have used a ND 1205 isolating buck converter 15 | to make 5V from the boats 12V supply. More on 16 | [isolation](https://sites.google.com/site/olewsaa/yacht-server-with-raspberry/a-note-on-isolation) 17 | in the web pages about this project. 18 | 19 | The file "Wifi-tank-level.ino" is the one used, the other Arduino sketches are older development 20 | versions included for reference. 21 | 22 | ![Breadboard](https://github.com/olewsaa/Yacht-computer/blob/master/img/Tank-level_bb.png 23 | "ESP-8266 breadboard layout") 24 | 25 | The pins named Data in the board have a different GPIO value, the table below show the mapping. 26 | 27 | | GPIO pin | Pin on board | Additional use | 28 | | :---------: | :-------------: | :------------: | 29 | | GPIO 16 | D0 | USER / WAKE | 30 | | GPIO 05 | D1 | | 31 | | GPIO 04 | D2 | | 32 | | GPIO 00 | D3 | FLASH | 33 | | GPIO 02 | D4 | TXD1 | 34 | | GPIO 14 | D5 | HSCLK | 35 | | GPIO 12 | D6 | HMISO | 36 | | GPIO 13 | D7 | RXD2 / HMOSI | 37 | | GPIO 15 | D8 | TXD2 / HCS | 38 | | GPIO 03 | RX | RXD0 | 39 | | GPIO 01 | TX | TXD0 | 40 | 41 | Some of the pins could not be used, GPIO 2 pin D4 is also used for transmit and when the 42 | sensor pull this up during init it fails to start the wifi. GPIO 00, pin D3 also has issues, 43 | GPIO 02 and GPIP 01 are also RX and TX, hence pulling them up or down during init is not good. 44 | GPIO 16 also has limitations. The net result is that there is a limited number of pins that can 45 | be used for input of this kind. Hence pins D2,D5,D6 and D7 are used as digital input pins. 46 | 47 | -------------------------------------------------------------------------------- /IoToB/Tank-level/WiFiClient-Tank-level-SignalK-v3.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Select board ESP-12E, NodeMCU 1.0 ESP12-E mmodule in the Arduino IDE. 4 | 5 | */ 6 | 7 | 8 | /* 9 | * The blue LED on the ESP-01 module is connected to GPIO1 10 | * (which is also the TXD pin; so we cannot use Serial.print() at the same time, 11 | * it also blinks with high frequency during upload or communication). 12 | 13 | * A total of 12 pins can be used for digital IO. However, as some have several uses 14 | * like 16 the built in led and 1 and 3 which is serial communication the number is less. 15 | * In practice 9 can be freely used. Also issues with GPIO pin 15. 16 | * 17 | */ 18 | // Right side : 19 | // GPIO_16 is equal to LED_BUILTIN. 20 | #define GPIO_16 16 // Can be used for output, controlled like any other Digital IO pin. 21 | #define GPIO_05 5 22 | #define GPIO_04 4 23 | #define GPIO_00 0 24 | #define GPIO_02 2 // Had issues with this, trigger blue led on the wifi module 25 | // 3.3V and GND between the above and below 26 | #define GPIO_14 14 27 | #define GPIO_12 12 28 | #define GPIO_13 13 29 | #define GPIO_15 15 30 | #define GPIO_03 03 // These two are for Serial communication. 31 | #define GPIO_01 01 // Using these for IO blocks of serial commmunication. 32 | 33 | // Left side : 34 | // Only GPIO 10 works. 35 | #define GPIO_10 10 36 | 37 | 38 | // Including WiFi stuff 39 | #include 40 | #include 41 | #include 42 | 43 | // Instanciate WiFi object 44 | ESP8266WiFiMulti WiFiMulti; 45 | // Instanciate UDP object 46 | WiFiUDP Udp; 47 | 48 | 49 | // Global variables 50 | 51 | // Wifi info 52 | const char * ssid = "openplotter"; 53 | const char * pwd = "blackpearl"; 54 | const uint16_t port = 55557; // SignalK uses this port. 55 | const char * host = "10.10.10.1"; // ip number of the SignalK server. 56 | 57 | // IO Pins for sensors 58 | // These are are the pins used : 59 | // GPIO 14, GPIO 12, GPIO_13, GPIO_04 60 | // On the card D5, D6, D7 and D2 61 | 62 | const short num_sens=4; 63 | const int sensor_pin[num_sens]={GPIO_14, GPIO_12, GPIO_13, GPIO_04}; 64 | 65 | 66 | // Set up the the system and configure the pins and set up the wifi. 67 | void setup() { 68 | // Serial.begin(115200); 69 | // Setting up the pins as digital IO pins. 70 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 71 | for (int j=0;j 40 | #include 41 | #include 42 | 43 | // Instanciate WiFi object 44 | ESP8266WiFiMulti WiFiMulti; 45 | // Instanciate UDP object 46 | WiFiUDP Udp; 47 | 48 | 49 | // Global variables 50 | 51 | // Wifi info 52 | const char * ssid = "openplotter"; 53 | const char * pwd = "blackpearl"; 54 | const uint16_t port = 55557; // SignalK uses this port. 55 | const char * host = "10.10.10.1"; // ip number of the SignalK server. 56 | 57 | // IO Pins for sensors 58 | // These are are the pins used : 59 | // GPIO 14, GPIO 12, GPIO_13, GPIO_04 60 | // On the card D5, D6, D7 and D2 61 | 62 | const short num_sens=4; 63 | const int sensor_pin[num_sens]={GPIO_14, GPIO_12, GPIO_13, GPIO_04}; 64 | 65 | 66 | // Set up the the system and configure the pins and set up the wifi. 67 | void setup() { 68 | // Serial.begin(115200); 69 | // Setting up the pins as digital IO pins. 70 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 71 | for (int j=0;j 6 | #include 7 | #include 8 | 9 | ESP8266WiFiMulti WiFiMulti; 10 | WiFiUDP Udp; 11 | 12 | void setup() { 13 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 14 | Serial.begin(115200); 15 | delay(10); 16 | 17 | // We start by connecting to a WiFi network 18 | WiFiMulti.addAP("TeamRocketHQ", "password"); 19 | 20 | Serial.println(); 21 | Serial.println(); 22 | Serial.print("Wait for WiFi... "); 23 | 24 | while(WiFiMulti.run() != WL_CONNECTED) { 25 | Serial.print("."); 26 | delay(500); 27 | } 28 | 29 | Serial.println(""); 30 | Serial.println("WiFi connected"); 31 | Serial.println("IP address: "); 32 | Serial.println(WiFi.localIP()); 33 | 34 | delay(500); 35 | } /* End setup */ 36 | 37 | 38 | void loop() { 39 | const uint16_t port = 55557; 40 | const char * host = "192.168.1.160"; // ip or dns 41 | double U; 42 | int val; 43 | char Us[6]; 44 | String cmd; 45 | 46 | 47 | val=analogRead(A0); // Read the analog input on the ESP2866. 48 | U=((double)val/(double)1023.0)*19.576; // Calibrated using a multimeter, check this value carefully. 49 | dtostrf(U,3,2,Us); 50 | /* 51 | Serial.println(Us); 52 | Serial.println(U,2); 53 | Serial.print("SignalK command"); 54 | */ 55 | cmd = "{\"updates\": [{\"$source\": \"ESP8266\",\"values\":[ {\"path\":\"electrical.service.voltage\",\"value\":"; 56 | cmd += Us; cmd+="}]}]}\0"; // Not sure if NULL is needed or not, but it's good custom to terminate with NULL: 57 | /* 58 | Serial.println(cmd); 59 | Serial.println(cmd.length()); 60 | Serial.print("connecting to using UDP"); Serial.print(host); Serial.print(":");Serial.println(port); 61 | */ 62 | 63 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED on while we transfer the data. 64 | // Some tricks to convert from String to character array as Udp.write will not accept string type argument. 65 | char cmd2[cmd.length()+1]; // Counting from zero, add one. 66 | Udp.beginPacket(host,port); // Connect to to server and prepare for UDP transfer. 67 | strncpy(cmd2,cmd.c_str(),sizeof(cmd2)); // Convert from String to array of characters. 68 | // Serial.println(cmd2); Serial.print(" Message har length: "); Serial.println(sizeof(cmd2)); 69 | Udp.write(cmd2); // Send the message to the SignalK server. 70 | Udp.endPacket(); // End the connection. 71 | 72 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH. 73 | 74 | Serial.println("wait 2 sec..."); 75 | delay(2000); 76 | } /* End infinite loop */ 77 | 78 | -------------------------------------------------------------------------------- /IoToB/Testing-and-Development/signalK-simulator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import time, socket 3 | # Initiate socket 4 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 | # socket.AF_INET is Internet 6 | # socket.SOCK_DGRAM) is UDP 7 | SignalK_UPD_PORT=55557 8 | SignalK_IP='192.168.1.169' 9 | print("Simulate SignalK") 10 | 11 | while True: 12 | # t=input("Please enter a number: ") 13 | # x = float(t) 14 | d=6.0*int(time.strftime("%S")) 15 | # SignalK uses radians, convert to degrees. 16 | d=d/180.0*3.141592 17 | s=5.3+0.4*int(time.strftime("%S")) 18 | print("send data ",format((d/3.14*180.0),'5.2f'),format(s,'5.2f')) 19 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"environment.wind.angleApparent","value":'+format(d,'5.3f')+'}]}]}' 20 | #print(SignalK) 21 | sock.sendto(SignalK, (SignalK_IP, SignalK_UPD_PORT)) 22 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"environment.wind.speedApparent","value":'+format(s,'5.3f')+'}]}]}' 23 | #print(SignalK) 24 | sock.sendto(SignalK, ('192.168.1.169', SignalK_UPD_PORT)) 25 | time.sleep(2) 26 | 27 | 28 | # SignalK : 29 | # environment.wind.speedApparent 30 | # environment.wind.angleApparent 31 | # 32 | # Remember to set up a SignalK input at port 55557 using the SignalK web interface. 33 | # Meny, Server, Connections, Add. Input type SignalK, Enabled yes, ID "Simulator", 34 | # Source UDP, Port 55557, No Self mapping. 35 | # 36 | -------------------------------------------------------------------------------- /IoToB/Testing-and-Development/signalK-test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # A simple Python script to test the SignalK server, e.g. that it will receive messages from 4 | # any source not only localhost. 5 | 6 | 7 | import time, socket 8 | 9 | 10 | # Initiate socket 11 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | # socket.AF_INET is Internet 13 | # socket.SOCK_DGRAM) is UDP 14 | 15 | 16 | 17 | print("Trying to send values to SignalK") 18 | 19 | while True: 20 | t=input("Please enter a number: ") 21 | x = float(t) 22 | 23 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"OrangePi.signalK.manual","value":'+format(x,'5.3f')+'}]}]}' 24 | print(SignalK) 25 | 26 | sock.sendto(SignalK, ('192.168.1.160', 55557)) 27 | 28 | -------------------------------------------------------------------------------- /IoToB/Testing-and-Development/sock-UDP-test.py: -------------------------------------------------------------------------------- 1 | import time, socket 2 | 3 | # A simple test to check if the ESP board communicates correct, 4 | # also to debug SignalK messages. 5 | 6 | # Initiate socket 7 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8 | # socket.AF_INET is Internet 9 | # socket.SOCK_DGRAM is UDP 10 | # socket.SOCK_STREAM is TCP 11 | 12 | print("Trying to receive values as SignalK") 13 | 14 | server_address = ('192.168.1.111', 10002) 15 | sock.bind(server_address) 16 | 17 | #sock.listen(1) 18 | while True: 19 | data, addr = sock.recvfrom(128) 20 | print "from", addr 21 | print data 22 | 23 | -------------------------------------------------------------------------------- /IoToB/Testing-and-Development/sock-test.py: -------------------------------------------------------------------------------- 1 | # A simple socket test that can come in handly when playing with ESP2866 and ESP32s. 2 | 3 | import socket 4 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 5 | # AF_INET Internet IP 6 | # SOCK_STREAM TCP 7 | 8 | 9 | server_address = ('192.168.1.111', 10002) 10 | sock.bind(server_address) 11 | sock.listen(1) 12 | while True: 13 | connection, client_address = sock.accept() 14 | # print connection 15 | data = connection.recv(128) 16 | print data 17 | 18 | 19 | connection.close() 20 | -------------------------------------------------------------------------------- /IoToB/Voltage-and-Current/README.md: -------------------------------------------------------------------------------- 1 | # Voltage and Current 2 | 3 | -------------------------------------------------------------------------------- /IoToB/Voltage-and-Current/WiFiClient-U-and-I-SignalK-v2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This sketch uses a ESP 8266 and ADS1115 to measure voltage and current and 3 | * sends messages to a SignalK server 4 | * 5 | * Select board ESP-12E, NodeMCU 1.0 ESP12-E module 6 | * 7 | */ 8 | // Including I2C and ADC board ADS1115 9 | #include 10 | #include 11 | 12 | // Including WiFi stuff 13 | #include 14 | #include 15 | #include 16 | 17 | // Instanciate an ads objects 18 | Adafruit_ADS1115 ads1(0x48); 19 | Adafruit_ADS1115 ads2(0x49); 20 | 21 | // Instanciate WiFi object 22 | ESP8266WiFiMulti WiFiMulti; 23 | WiFiUDP Udp; 24 | 25 | 26 | void setup() { 27 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 28 | Serial.begin(115200); 29 | delay(10); 30 | 31 | // Set up the first ADS 1115 gain 32 | ads1.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV 33 | ads1.begin(); 34 | Serial.println("ADS 1115 no 1 set up"); 35 | ads2.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV 36 | ads2.begin(); 37 | Serial.println("ADS 1115 no 2 set up"); 38 | 39 | // We start by connecting to a WiFi network 40 | WiFiMulti.addAP("TeamRocketHQ", "password"); 41 | 42 | Serial.println(); 43 | Serial.println(); 44 | Serial.print("Wait for WiFi... "); 45 | 46 | while(WiFiMulti.run() != WL_CONNECTED) { 47 | Serial.print("."); 48 | delay(500); 49 | } 50 | 51 | Serial.println(""); 52 | Serial.println("WiFi connected"); 53 | Serial.println("IP address: "); 54 | Serial.println(WiFi.localIP()); 55 | 56 | delay(500); 57 | } /* End setup */ 58 | 59 | 60 | 61 | void Send_to_SignalK(String path, double value){ 62 | 63 | // Settings for SignalK port and SignalK server. 64 | const uint16_t port = 55557; // SignalK uses this port. 65 | const char * host = "192.168.1.160"; // ip number of the SignalK server. 66 | String cmd; 67 | char valuestring[6]; 68 | 69 | cmd = "{\"updates\": [{\"$source\": \"ESP8266\",\"values\":[ {\"path\":\""; 70 | cmd += path; cmd += "\","; cmd += "\"value\":"; 71 | dtostrf(value,3,2,valuestring); // Convert double to a string 72 | cmd += valuestring; 73 | cmd += "}]}]}\0"; 74 | /* 75 | Serial.println(cmd); 76 | Serial.println(cmd.length()); 77 | */ 78 | 79 | char cmdc[cmd.length()+1]; // Convert the String to an array of characters. 80 | Udp.beginPacket(host,port); // Connect to to server and prepare for UDP transfer. 81 | strncpy(cmdc,cmd.c_str(),sizeof(cmdc)); // Convert from String to array of characters. 82 | Serial.println(cmdc); Serial.print(" Message har length: "); Serial.println(sizeof(cmdc)); 83 | Udp.write(cmdc); // Send the message to the SignalK server. 84 | Udp.endPacket(); // End the connection. 85 | delay(10); // Short delay to recover. 86 | } /* End Send_to_SignalK */ 87 | 88 | 89 | 90 | void Measure_and_Send_U(int inputno) { 91 | double U; 92 | int val,offset; 93 | 94 | /* 95 | * Voltage is measured using the single ADC input on the ESP8266 chip. 96 | * However, this routine is generic and it can easily change to ADS1115. 97 | */ 98 | offset=-1; // Differ from board to board, make your own calibration. 99 | val=analogRead(A0); // Read the analog input on the ESP8266. 100 | val+=offset; 101 | U=((double)val/(double)1023.0)*18.0; // Calibrated using a multimeter, check this value carefully. 102 | 103 | Send_to_SignalK("electrical.service.voltage",U); 104 | } 105 | 106 | 107 | void Measure_and_Send_I(int inputno) { 108 | double I; 109 | int val, offset; 110 | 111 | if (inputno==1) { 112 | // Read ADC and calculate the equivalt current in Amps. 113 | offset=-140; // Differ from sensor to sensor, calibration is needed. 114 | val=ads1.readADC_Differential_0_1(); // There are two possibilities in differential mode, 01 and 23. 115 | Serial.println(val); 116 | val+=offset; 117 | I = (double)val/(double)32766*160; // Calibrated with a multimeter. 118 | Send_to_SignalK("electrical.service.HKS2010",I); 119 | } 120 | if (inputno==2) { 121 | offset=-200; 122 | val=ads1.readADC_Differential_2_3(); // There are two possibilities in differential mode, 01 and 23. 123 | Serial.println(val); 124 | val+=offset; 125 | I = (double)val/(double)32766*11.5; // Calibrated with a multimeter. 126 | Send_to_SignalK("electrical.service.ACS712",I); 127 | } 128 | if (inputno==3) { 129 | offset=-650; 130 | val=ads2.readADC_Differential_0_1(); // There are two possibilities in differential mode 01 and 23. 131 | Serial.println(val); 132 | val+=offset; 133 | I = (double)val/(double)32766*33.0; // Calibrated with a multimeter. 134 | Send_to_SignalK("electrical.service.WCS1800",I); 135 | } 136 | } 137 | 138 | 139 | void loop() { 140 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED on while we transfer the data. 141 | Measure_and_Send_U(1); // Get the voltage and send it to SignalK. 142 | Measure_and_Send_I(1); // Get the current and send it to SignalK. 143 | Measure_and_Send_I(2); // Get the current and send it to SignalK. 144 | Measure_and_Send_I(3); // Get the current and send it to SignalK. 145 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH. 146 | 147 | Serial.println("wait 2 sec..."); // This high refresh rate put a load in the SignalK server. 148 | delay(2000); 149 | } /* End infinite loop */ 150 | 151 | -------------------------------------------------------------------------------- /IoToB/Voltage-and-Current/WiFiClient-U-and-I-SignalK.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This sketch uses a ESP 8266 and ADS1115 to measure voltage and current and 3 | * sends messages to a SignalK server 4 | * 5 | */ 6 | // Including I2C and ADC board ADS1115 7 | #include 8 | #include 9 | 10 | // Including WiFi stuff 11 | #include 12 | #include 13 | #include 14 | 15 | // Instanciate an ads object 16 | Adafruit_ADS1115 ads; 17 | 18 | // Instanciate WiFi object 19 | ESP8266WiFiMulti WiFiMulti; 20 | WiFiUDP Udp; 21 | 22 | 23 | void setup() { 24 | pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output 25 | Serial.begin(115200); 26 | delay(10); 27 | 28 | // Set up the ADS 1115 gain 29 | ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 0.0625mV 30 | ads.begin(); 31 | Serial.println("ADS 1115 set up"); 32 | 33 | // We start by connecting to a WiFi network 34 | WiFiMulti.addAP("TeamRocketHQ", "password"); 35 | 36 | Serial.println(); 37 | Serial.println(); 38 | Serial.print("Wait for WiFi... "); 39 | 40 | while(WiFiMulti.run() != WL_CONNECTED) { 41 | Serial.print("."); 42 | delay(500); 43 | } 44 | 45 | Serial.println(""); 46 | Serial.println("WiFi connected"); 47 | Serial.println("IP address: "); 48 | Serial.println(WiFi.localIP()); 49 | 50 | delay(500); 51 | } /* End setup */ 52 | 53 | 54 | 55 | void Send_to_SignalK(String path, double value){ 56 | 57 | // Settings for SignalK port and SignalK server. 58 | const uint16_t port = 55557; // SignalK uses this port. 59 | const char * host = "192.168.1.160"; // ip number of the SignalK server. 60 | String cmd; 61 | char valuestring[6]; 62 | 63 | cmd = "{\"updates\": [{\"$source\": \"ESP8266\",\"values\":[ {\"path\":\""; 64 | cmd += path; cmd += "\","; cmd += "\"value\":"; 65 | dtostrf(value,3,2,valuestring); // Convert double to a string 66 | cmd += valuestring; 67 | cmd += "}]}]}\0"; 68 | /* 69 | Serial.println(cmd); 70 | Serial.println(cmd.length()); 71 | */ 72 | 73 | char cmdc[cmd.length()+1]; // Convert the String to an array of characters. 74 | Udp.beginPacket(host,port); // Connect to to server and prepare for UDP transfer. 75 | strncpy(cmdc,cmd.c_str(),sizeof(cmdc)); // Convert from String to array of characters. 76 | //Serial.println(cmdc); Serial.print(" Message har length: "); Serial.println(sizeof(cmdc)); 77 | Udp.write(cmdc); // Send the message to the SignalK server. 78 | Udp.endPacket(); // End the connection. 79 | delay(10); // Short delay to recover. 80 | } /* End Send_to_SignalK */ 81 | 82 | 83 | 84 | void Measure_and_Send_U(int inputno) { 85 | double U; 86 | int val,offset; 87 | 88 | /* 89 | * Voltage is measured using the single ADC input on the ESP8266 chip. 90 | * However, this routine is generic and it can easily change to ADS1115. 91 | */ 92 | offset=-1; // Differ from board to board, make your own calibration. 93 | val=analogRead(A0); // Read the analog input on the ESP8266. 94 | val+=offset; 95 | U=((double)val/(double)1023.0)*19.576; // Calibrated using a multimeter, check this value carefully. 96 | 97 | Send_to_SignalK("electrical.service.voltage",U); 98 | } 99 | 100 | 101 | void Measure_and_Send_I(int inputno) { 102 | double I; 103 | int val, offset; 104 | 105 | if (inputno==1) { 106 | // Read ADC and calculate the equivalt current in Amps. 107 | offset=250; // Differ from sensor to sensor, calibration is needed. 108 | val=ads.readADC_Differential_0_1(); // There are two possibilities in differential mode, 0-1. 109 | //Serial.println(val); 110 | val+=offset; 111 | I = (double)val/(double)32766*14.18; // Calibrated with a multimeter. 112 | Send_to_SignalK("electrical.service.ACS712",I); 113 | } 114 | if (inputno==2) { 115 | offset=-14000; 116 | val=ads.readADC_Differential_2_3(); // There are two possibilities in differential mode, 2-3. 117 | //Serial.println(val); 118 | val+=offset; 119 | I = (double)val/(double)32766*117.0; // Calibrated with a multimeter. 120 | Send_to_SignalK("electrical.service.WCS1800",I); 121 | } 122 | } 123 | 124 | 125 | void loop() { 126 | digitalWrite(LED_BUILTIN, LOW); // Turn the LED on while we transfer the data. 127 | Measure_and_Send_U(1); // Get the voltage and send it to SignalK. 128 | Measure_and_Send_I(1); // Get the current and send it to SignalK. 129 | Measure_and_Send_I(2); // Get the current and send it to SignalK. 130 | digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH. 131 | 132 | //Serial.println("wait 2 sec..."); // This high refrech rate put a load in the SignalK server. 133 | delay(2000); 134 | } /* End infinite loop */ 135 | 136 | -------------------------------------------------------------------------------- /MCP3008/README.md: -------------------------------------------------------------------------------- 1 | 2 | This direcory contain files used with the MCP3008 chip. 3 | -------------------------------------------------------------------------------- /MCP3008/current-diffmeasure.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time, socket 4 | 5 | # Import SPI library (for hardware SPI) and MCP3008 library. 6 | import Adafruit_GPIO.SPI as SPI 7 | import Adafruit_MCP3008 8 | 9 | 10 | # Initiate socket 11 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | 13 | # Software SPI configuration: 14 | # CLK = 18 15 | # MISO = 23 16 | # MOSI = 24 17 | # CS = 25 18 | # mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) 19 | 20 | # Hardware SPI configuration: 21 | SPI_PORT = 0 22 | SPI_DEVICE = 0 23 | mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 24 | 25 | SignalK="" 26 | 27 | while True: 28 | # Grab the difference between channel 0 and 1 (i.e. channel 0 minus 1). 29 | # Note you can specify any value in 0-7 to grab other differences: 30 | # - 0: Return channel 0 minus channel 1 31 | # - 1: Return channel 1 minus channel 0 32 | # - 2: Return channel 2 minus channel 3 33 | # - 3: Return channel 3 minus channel 2 34 | # - 4: Return channel 4 minus channel 5 35 | # - 5: Return channel 5 minus channel 4 36 | # - 6: Return channel 6 minus channel 7 37 | # - 7: Return channel 7 minus channel 6 38 | for k in range(2): 39 | # Should have made an array of names and values, but there is only two, 40 | # quick cut/paste is faster. 41 | if k == 0: 42 | value = mcp.read_adc_difference(1) 43 | i=float((value)/1023.0)*21.0 44 | #print 'Channel 0 minus 1: {0}'.format(value),' equal ',format(i,'.2f'),'A' 45 | SignalK='{"updates": [{"$source": "SPI.MCP3008","values":[ {"path": "electrical.WCS1800.current","value":'+format(i,'5.3f')+'}]}]}' 46 | #print SignalK 47 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 48 | if k == 1: 49 | value = mcp.read_adc_difference(3) 50 | i=float((value)/1023.0)*12.0 51 | #print 'Channel 3 minus 2: {0}'.format(value),' equal ',format(i,'.2f'),'A' 52 | SignalK='{"updates": [{"$source": "SPI.MCP3008","values":[ {"path": "electrical.ACS712.current","value":'+format(i,'5.3f')+'}]}]}' 53 | #print SignalK 54 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 55 | time.sleep(1) 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /MCP3008/current-singlended-measure.py: -------------------------------------------------------------------------------- 1 | # Simple example of reading the MCP3008 analog input channels and printing 2 | # them all out. 3 | # Author: Tony DiCola 4 | # License: Public Domain 5 | import time 6 | 7 | # Import SPI library (for hardware SPI) and MCP3008 library. 8 | import Adafruit_GPIO.SPI as SPI 9 | import Adafruit_MCP3008 10 | 11 | 12 | # Software SPI configuration: 13 | CLK = 18 14 | MISO = 23 15 | MOSI = 24 16 | CS = 25 17 | mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) 18 | 19 | # Hardware SPI configuration: 20 | SPI_PORT = 0 21 | SPI_DEVICE = 0 22 | mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 23 | 24 | 25 | while True: 26 | value = mcp.read_adc(1) 27 | i=(value-510)*0.09 28 | print 'Value ',value,' current ',i,' A' 29 | time.sleep(1) 30 | -------------------------------------------------------------------------------- /MCP3008/differential.py: -------------------------------------------------------------------------------- 1 | # Simple example of reading the MCP3008 analog input channels using its 2 | # differential mode. Will print the difference of channel 0 and 1. 3 | # Author: Tony DiCola 4 | # License: Public Domain 5 | import time 6 | 7 | # Import SPI library (for hardware SPI) and MCP3008 library. 8 | import Adafruit_GPIO.SPI as SPI 9 | import Adafruit_MCP3008 10 | 11 | 12 | # Software SPI configuration: 13 | # CLK = 18 14 | # MISO = 23 15 | # MOSI = 24 16 | # CS = 25 17 | # mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) 18 | 19 | # Hardware SPI configuration: 20 | SPI_PORT = 0 21 | SPI_DEVICE = 0 22 | mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 23 | 24 | print('Press Ctrl-C to quit...') 25 | while True: 26 | # Grab the difference between channel 0 and 1 (i.e. channel 0 minus 1). 27 | # Note you can specify any value in 0-7 to grab other differences: 28 | # - 0: Return channel 0 minus channel 1 29 | # - 1: Return channel 1 minus channel 0 30 | # - 2: Return channel 2 minus channel 3 31 | # - 3: Return channel 3 minus channel 2 32 | # - 4: Return channel 4 minus channel 5 33 | # - 5: Return channel 5 minus channel 4 34 | # - 6: Return channel 6 minus channel 7 35 | # - 7: Return channel 7 minus channel 6 36 | value = mcp.read_adc_difference(0) 37 | print('Channel 0 minus 1: {0}'.format(value)) 38 | time.sleep(0.5) 39 | -------------------------------------------------------------------------------- /MCP3008/simpletest.py: -------------------------------------------------------------------------------- 1 | # Simple example of reading the MCP3008 analog input channels and printing 2 | # them all out. 3 | # Author: Tony DiCola 4 | # License: Public Domain 5 | import time 6 | 7 | # Import SPI library (for hardware SPI) and MCP3008 library. 8 | import Adafruit_GPIO.SPI as SPI 9 | import Adafruit_MCP3008 10 | 11 | 12 | # Software SPI configuration: 13 | CLK = 18 14 | MISO = 23 15 | MOSI = 24 16 | CS = 25 17 | mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI) 18 | 19 | # Hardware SPI configuration: 20 | SPI_PORT = 0 21 | SPI_DEVICE = 0 22 | mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE)) 23 | 24 | 25 | print('Reading MCP3008 values, press Ctrl-C to quit...') 26 | # Print nice channel column headers. 27 | print('| {0:>4} | {1:>4} | {2:>4} | {3:>4} | {4:>4} | {5:>4} | {6:>4} | {7:>4} |'.format(*range(8))) 28 | print('-' * 57) 29 | # Main program loop. 30 | while True: 31 | # Read all the ADC channel values in a list. 32 | values = [0]*8 33 | for i in range(8): 34 | # The read_adc function will get the value of the specified channel (0-7). 35 | values[i] = mcp.read_adc(i) 36 | # Print the ADC values. 37 | print('| {0:>4} | {1:>4} | {2:>4} | {3:>4} | {4:>4} | {5:>4} | {6:>4} | {7:>4} |'.format(*values)) 38 | # Pause for half a second. 39 | time.sleep(0.5) 40 | -------------------------------------------------------------------------------- /NTP SignalK source/get-date-from-SignalK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os, json, requests 3 | 4 | # Script to set the time and date from SignalK. The RPi have no internal 5 | # real time battery powered clock to keep time. Without internet 6 | # connection it cannot set its clock. When a separate GPS is not 7 | # connected it ned to ask the SignalK server for time data. 8 | 9 | # 10 | # Setting UTC timezone via CLI : 11 | # sudo rm /etc/localtime 12 | # sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime 13 | # 14 | # timedatectl list-timezones 15 | # 16 | # UTC or Europe/Oslo 17 | # 18 | # sudo timedatectl set-timezone Europe/Oslo 19 | # sudo timedatectl set-timezone UTC 20 | # 21 | 22 | resp = requests.get('http://demo.signalk.org/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 23 | 24 | #resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 25 | 26 | 27 | data = json.loads(resp.content) 28 | print(data) 29 | #cmd="sudo date -s "+data 30 | #os.system(cmd) 31 | Y=data[0:4] 32 | M=data[5:7] 33 | D=data[8:10] 34 | h=data[11:13] 35 | m=data[14:16] 36 | s=data[17:24] 37 | print(D,"/",M,"-",Y," ",h,":",m,":",s) 38 | 39 | -------------------------------------------------------------------------------- /NTP SignalK source/ntp.conf: -------------------------------------------------------------------------------- 1 | # /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help 2 | 3 | driftfile /var/lib/ntp/ntp.drift 4 | 5 | # Leap seconds definition provided by tzdata 6 | leapfile /usr/share/zoneinfo/leap-seconds.list 7 | 8 | # Specify one or more NTP servers. 9 | # 10 | # Local clock, this get updated from GPS/SignalK if no 11 | # internet. 12 | server 10.10.10.1 iburst 13 | fudge 10.10.10.1 stratum 8 14 | 15 | # From a pool, works only with an internet connection. 16 | ntp.justervesenet.no 17 | ntp.online.no 18 | ntp.uio.no 19 | pool 0.ubuntu.pool.ntp.org 20 | -------------------------------------------------------------------------------- /PCF8574/Readme.md: -------------------------------------------------------------------------------- 1 | Files related to the on/off IO pin card based on the chip PCF8574 and PCF8574A 2 | 3 | -------------------------------------------------------------------------------- /PCF8574/readout.py: -------------------------------------------------------------------------------- 1 | # Distributed with a free-will license. 2 | # Use it any way you want, profit or free, provided it fits in the licenses of its associated works. 3 | # PCF8574 4 | # This code is designed to work with the PCF8574_LBAR_I2CL I2C Mini Module available from ControlEverything.com. 5 | # https://www.controleverything.com/products 6 | 7 | import smbus 8 | import time 9 | 10 | # Get I2C bus 11 | bus = smbus.SMBus(1) 12 | 13 | # PCF8574 address, 0x20(32) 14 | # PCF8574A address, 0x38(56) 15 | PCF8574A=0x38 16 | # 0xFF All pins configured as inputs 17 | bus.write_byte(PCF8574A, 0xFF) 18 | 19 | time.sleep(0.5) 20 | 21 | # PCF8574A address, 0x38(56) 22 | # Read data back, 1 byte 23 | data = bus.read_byte(0x38) 24 | 25 | 26 | # Convert the data 27 | data = (data & 0xFF) 28 | 29 | while True: 30 | data = bus.read_byte(0x38) 31 | data = (data & 0xFF) 32 | bus.write_byte(0x38,0xfe) 33 | for i in range(0, 8) : 34 | # print 'data', bin(data),' - ', bin(data & (2**i)) 35 | # print("{0:b}".format(data),' - ',"{:#010b}".format(data&(2**i))) 36 | # print"{0:b}".format(data),' - ',"{:08b}".format(data&(2**i)),(data & (2 ** i))%data 37 | if (data & (2 ** i)) == 0 : 38 | print "I/O Pin %d State is LOW" %(i) 39 | else : 40 | print "I/O Pin %d State is HIGH" %(i) 41 | time.sleep(0.2) 42 | print 'done' 43 | bus.write_byte(0x38,0xff) 44 | time.sleep(1) 45 | 46 | -------------------------------------------------------------------------------- /PCF8574/tank-level.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | # Aug 2017 OWS 5 | # Adapted to work with the PCF8574A based module. 6 | 7 | import smbus, time, socket 8 | 9 | # Get I2C bus 10 | bus = smbus.SMBus(1) 11 | 12 | # Initiate socket 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 14 | 15 | # PCF8574 address, 0x20(32) 16 | # PCF8574A address, 0x38(56) 17 | PCF8574A=0x38 18 | # 0xFF All pins configured as inputs 19 | bus.write_byte(PCF8574A, 0xFF) 20 | 21 | time.sleep(0.5) 22 | 23 | # PCF8574A address, 0x38(56) 24 | # Read data back, 1 byte 25 | data = bus.read_byte(0x38) 26 | 27 | num_sensors = 3 28 | interval = 1.0/float(num_sensors) 29 | 30 | SignalK="" 31 | while True: 32 | data = bus.read_byte(0x38) 33 | data = (data & 0xFF) 34 | # Pin 2,3 and 4 are used for sensors, 1/3, 2/3 and full. 35 | for i in range(2, 4) : 36 | level=0 37 | if data & (2 ** 2) == 0 : 38 | level=level+interval 39 | if data & (2 ** 3) == 0: 40 | level=level+interval 41 | if data & (2 ** 4) == 0: 42 | level=level+interval 43 | bus.write_byte(0x38,0xff) 44 | 45 | SignalK='{"updates": [{"$source": "I2C.PCF8574A","values":[ {"path": "tanks.freshWater.*.currentLevel","value":'+format(level,'5.3f')+'}]}]}' 46 | sock.sendto(SignalK, ('127.0.0.1', 55557)) 47 | time.sleep(1) 48 | 49 | 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yacht-computer project 2 | ## Yacht-server background 3 | 4 | Every yacht need to have a server (or servers) on board. There are 5 | many need to be fulfilled, of which OpenPlotter cover a significant 6 | fraction, OpenCPN and SignalK are prime examples. There are still gaps 7 | to be filled. Monitoring of equipment like engine, tank levels, 8 | temperatures, voltage and current etc etc. The list is long. In 9 | addition comes the need to a server to handle the comunication and a 10 | file server on board. A central place to dump all pictures and video 11 | from cameras and modiles and to stock up these with audiobooks and 12 | videos. 13 | 14 | The Raspberry Pi or similar types are ideal suited for this purpose, 15 | very small and affordable which mean that severel servers can be 16 | deployed without high cost og power cunsumption. 17 | 18 | The goal is to replace as much as possible of the yacht instruments 19 | with servers (Raspberry Pi etc) and laptops, pads and mobile 20 | phones. This part her focuses on interfacing sensors and such with the 21 | Rasperry Pi. I keep a [web page about this 22 | project](https://sites.google.com/site/olewsaa/yacht-server). 23 | 24 | ## OpenPlotter and OpenCPN 25 | 26 | The server part is running OpenPlotter which takes care of almost all the server related functions and services. The server hosts SignalK which provide web server that allow display of data on web pages both local and for any client that want to connect. 27 | 28 | The server also run OpenCPN as a chart plotter on board. The OpenCPN accept various signals from OpenPlotter and display GPS positions to update the boats position and accept AIS NMEA signals again to be plotted. All of this is nicely run on a Raspberry Pi. 29 | 30 | ## HF/SSB radio control 31 | 32 | The pat directory contain software used to control the HF/SSB radio, including winlink email which uses the pat software. 33 | 34 | ## Wifi gateway - wifi2wifi 35 | 36 | This project is to use a Pi as a gateway to the internet. A high gain wifi antenna that usually connect using USB connect to a remote access point. Then the gateway provieds a local network onboard to which all client on board can connect to. 37 | 38 | ## Communication server 39 | 40 | Another Raspberry Pi is set up to handle communication as this might prove to much for the one runnng both Openplotter and OpenCPN. This is a separate [project](https://sites.google.com/site/olewsaa/yacht-server/raspberry-pi-as-a-router-gateway). I have taken some ideas from the famous RedBox, which can do very much more than my litte project. 41 | 42 | ## File server 43 | 44 | A little file server with Bluetooth interface ta facilitate easy transfer of pictures and video from the mobiles, teenagers are happy to dump selected files onto a file server, but refuse to let a cable enter their phones. In addtion the file server can host autobooks, music and films. A large USB attached SSD is a good way to get high storage capacity. 45 | 46 | ## Server and IoT sensors 47 | 48 | Files and documents related to the Yacht computer project. This git 49 | repository contain only the actual files used, the project is 50 | described 51 | [here](https://sites.google.com/site/olewsaa/yacht-server-with-raspberry) 52 | and for the versions installed or in process of being installed 53 | [here](https://sites.google.com/site/olewsaa/yacht-server). 54 | 55 | ## IoToB 56 | The Internet of Things directory contains files for the IoT approach to the project. 57 | Which has become the major part of this project. 58 | 59 | ## Development of data systems and IoT sensors 60 | 61 | Some of this might find its way into the Openploter project (but 62 | already it provides a platform for collection of information from the 63 | networked(wifi) sensors on board, SignalK server end associated web 64 | server. Some are demo files showing how to use a type of sensor or 65 | other feature. However, this project it basically to show how you 66 | instrument the boat with simple and cost effective solutions. 67 | 68 | Personally I have opted for a Internet of Things on Board (ioToB) 69 | where the sensors are autonomous units that sends off the data to the 70 | central server over wifi (SignalK server that comes with the 71 | OpenPlotter distro). 72 | 73 | ## Learning to use chips and sensors 74 | 75 | Some subproject underway with inital testing include: 76 | 77 | 1. PCF8574 is a digital input output chip. Used to measure water in tanks. 78 | 2. MCP3008 is a 10 bit Analog to Digital Converter (ADC). Has many uses like voltage and current. 79 | 3. ADS1115 is a 16 bit ADC, a high precision ADC for usage where more than 10 bit is needed. 80 | 4. DS18B20 is a one wire temperature device, a nice device for monitoring temperatures. 81 | 5. ESP-8622 is the IoToB chip/board of choice. Small, simple, almost costless. 82 | 6. ESP-32 is one step up, far more connections and still small and very cost effective. 83 | 84 | -------------------------------------------------------------------------------- /RPi-configfiles/Readme.md: -------------------------------------------------------------------------------- 1 | # Config files for Raspberry Pi 2 | 3 | There are always some minor settings that can easily be overlooked. Most things comes nicely packaged with the [NOOB Openplotter distro](http://www.sailoog.com/blog-categories/openplotter-rpi). 4 | 5 | ## Forwarding 6 | If laptop or other clients are connected to the OpenPlotter node requests to other destinations need to be forwarded, either to other 7 | nodes on the wifi range or via the Ethernet interface to a node which connect to the internet like a router (raspap using a RPi3). 8 | Change the line in /etc/sysctl.conf to read : net.ipv4.ip_forward = 1 9 | 10 | ## Lost access point 11 | As always, updates and upgrades are not always safe. Most major 12 | disasters happen after an update or upgrade, where important services 13 | are affected. After an upgrade in May 2019 I lost the access 14 | point, all my IoToB devices failed to connect. 15 | Some search at various sites and forums was needed to resolve 16 | this. The actual fix was actually simple, just replacing a single line 17 | in a config file. 18 | 19 | ### Script file for dnsmadq 20 | The file /etc/init.d/dnsmasq had a line that needed to be replaced, the line 115 21 | needed to be replaced. The actual file is presented in this directory. The original 22 | line is commented out and a working line is added. 23 | 24 | Some web references: 25 | 26 | - [openmarine forum, thread about lost AP](http://forum.openmarine.net/showthread.php?tid=1083). 27 | 28 | - [Some hints about AP config](https://forums.kali.org/showthread.php?38920-Access-point-configuration-problem-on-RPi3). 29 | 30 | - [Failing to start dnsmasq](https://www.raspberrypi.org/forums/viewtopic.php?t=128449). 31 | 32 | - ["dnsmasq not starting" at discourse](https://discourse.pi-hole.net/t/dnsmasq-not-starting/10523/13), containing pointer to the line that caused the problem. 33 | 34 | - [Debian bug tracker](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=858506), with the actual line. 35 | 36 | This last two references are the one that actually showed the error in the dnsmasq script (as always the devil is in the details). 37 | 38 | ### Config files for Access point and dhcp 39 | 40 | As the Openplotter settings did not work as expected (Network mode: 41 | RPi3: AP+client), hence I did the settings with config files. This is not the 42 | proper way, but a hack needed to get things working. There are several 43 | services working together and since I want an access point using the 44 | wlan device and connect to the internet via an Ethernet cable the 45 | settings is somewhat complex. In addition I do not want bridging from 46 | the wlan to the internet. The wlan is a closed wireless net for the 47 | Internet of Things on Board. The following is a list of files I 48 | modified to get things to work, in addition the the script dnsmasq. 49 | - /etc/dhcpcd.conf 50 | - /etc/hostapd/hostapd.conf 51 | - /etc/dnsmasq.conf 52 | 53 | After modified these files I discovered that the access point was not enabled at reboot. 54 | A systemd command to enable the service was issued ```systemctl enable hostapd```. 55 | After this the access point were back and IoToB devices would work. 56 | -------------------------------------------------------------------------------- /RPi-configfiles/dhcpcd.conf: -------------------------------------------------------------------------------- 1 | # A sample configuration for dhcpcd. 2 | # See dhcpcd.conf(5) for details. 3 | 4 | # Allow users of this group to interact with dhcpcd via the control socket. 5 | #controlgroup wheel 6 | 7 | # Inform the DHCP server of our hostname for DDNS. 8 | hostname 9 | 10 | # Use the hardware address of the interface for the Client ID. 11 | clientid 12 | # or 13 | # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. 14 | # Some non-RFC compliant DHCP servers do not reply with this set. 15 | # In this case, comment out duid and enable clientid above. 16 | #duid 17 | 18 | # Persist interface configuration when dhcpcd exits. 19 | persistent 20 | 21 | # Rapid commit support. 22 | # Safe to enable by default because it requires the equivalent option set 23 | # on the server to actually work. 24 | option rapid_commit 25 | 26 | # A list of options to request from the DHCP server. 27 | option domain_name_servers, domain_name, domain_search, host_name 28 | option classless_static_routes 29 | # Most distributions have NTP support. 30 | option ntp_servers 31 | # Respect the network MTU. This is applied to DHCP routes. 32 | option interface_mtu 33 | 34 | # A ServerID is required by RFC2131. 35 | require dhcp_server_identifier 36 | 37 | # Generate Stable Private IPv6 Addresses instead of hardware based ones 38 | slaac private 39 | 40 | # Example static IP configuration: 41 | #interface eth0 42 | #static ip_address=192.168.0.10/24 43 | #static ip6_address=fd51:42f8:caae:d92e::ff/64 44 | #static routers=192.168.0.1 45 | #static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1 46 | 47 | # It is possible to fall back to a static IP if DHCP fails: 48 | # define static profile 49 | #profile static_eth0 50 | #static ip_address=192.168.1.23/24 51 | #static routers=192.168.1.1 52 | #static domain_name_servers=192.168.1.1 53 | 54 | # fallback to static profile on eth0 55 | #interface eth0 56 | #fallback static_eth0 57 | 58 | interface wlan1 59 | static ip_address=10.10.10.1/24 60 | static routers=10.10.10.1 61 | static domain_name_servers=10.10.10.1 62 | 63 | denyinterfaces wlan1 usb0 64 | 65 | interface usb0 66 | static ip_address=192.168.42.100/24 67 | static routers=192.168.42.129 68 | metric 400 69 | -------------------------------------------------------------------------------- /RPi-configfiles/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | interface=wlan1 2 | no-dhcp-interface=lo,wlan0,usb0 3 | no-resolv 4 | server=8.8.8.8 5 | dhcp-range=10.10.10.50,10.10.10.200,12h 6 | -------------------------------------------------------------------------------- /RPi-configfiles/hostapd.conf: -------------------------------------------------------------------------------- 1 | interface=wlan1 2 | ssid=openplotter 3 | hw_mode=g 4 | channel=6 5 | macaddr_acl=0 6 | auth_algs=1 7 | ignore_broadcast_ssid=0 8 | wpa=2 9 | wpa_passphrase=password 10 | wpa_key_mgmt=WPA-PSK 11 | wpa_pairwise=TKIP 12 | rsn_pairwise=CCMP 13 | -------------------------------------------------------------------------------- /RPi-settings.md: -------------------------------------------------------------------------------- 1 | # Settings for Raspberry Pi and OpenCPN 2 | 3 | ## Config settings 4 | 5 | ### Screen / Display 6 | The screen settings can be a trial and error exercise. Which OpenGL setting and other display related 7 | settings to set are not intuitive and some hints can reduce the trial and error step. As there are both 8 | HDMI to HDMI, HDI to DVI and other cables and monitors availale there is not a "one size fit all" setting. 9 | Some help can be found here: [using TV as monitor](https://www.pcworld.com/article/2924203/use-your-tv-as-a-computer-monitor-everything-you-need-to-know.html). 10 | 11 | Open the Raspberry menu, preferences and old raspi-config. 12 | Select option 7 advances options and open it. 13 | - Overscan, this can help if the screen appear too large for the display. I had to set this option when 14 | connecting to a TV HDMI input (using a computer terminal with HDMI=>DVI adaper is fixes this automatic). 15 | - Memory split, the recommendation is to use 64 MiB. There are only 1024 MiB in total so setting this too 16 | high may reduce the amount of memory for OpenCPN and OS. Some gamers suggest 256 MiB. 17 | - Resolution, a monitor might communicate with the GPU (graphical processing Unit) and suggest a default. 18 | In other cases you might select a suitable resolution, a HD TV can tackle 1920x1080. 19 | - GL driver, OpenGL is needed, both Full KMS driver and Fake KMS driver works, suggestions from gamers 20 | is to use the full KMS. 21 | 22 | To test the OpenGL driver the mesa-utils come in handy. Install using `apt install mesa-utils`. Starting the nice 23 | simple test glxgears should produce cogwheels running smoothly on the display. In my system it performs at about 60 24 | frames per second. 25 | 26 | 27 | ### Pi Configuration 28 | The graphical config tool offers a range of settings. It is generally a good idea to disable interfaces services that 29 | are not needed. I have turned off the following services: 30 | - camera 31 | - VNC 32 | - SPI 33 | - Serial 34 | - 1-wire 35 | The important one is secure shell, SSH. Set this to enable if you want to login to the system. 36 | 37 | ### Lost access point after upgrade 38 | This topic is covered i the section about RPi config files. After an upgrade I lost the 39 | access point set by OpenPlotter. It took some manoeuvring to get things back. 40 | -------------------------------------------------------------------------------- /SignalK-tests/signalK-simulator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import time, socket 3 | # Initiate socket 4 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 5 | # socket.AF_INET is Internet 6 | # socket.SOCK_DGRAM) is UDP 7 | SignalK_UPD_PORT=20220 8 | SignalK_IP='192.168.1.169' 9 | print("Simulate SignalK") 10 | 11 | while True: 12 | # t=input("Please enter a number: ") 13 | # x = float(t) 14 | d=135+int(time.strftime("%S")) 15 | s=5.3+0.2*int(time.strftime("%S")) 16 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"environment.wind.angleApparent","value":'+format(d,'5.3f')+'}]}]}' 17 | print(SignalK) 18 | sock.sendto(SignalK, (SignalK_IP, SignalK_UPD_PORT)) 19 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"environment.wind.speedApparent","value":'+format(s,'5.3f')+'}]}]}' 20 | print(SignalK) 21 | sock.sendto(SignalK, ('192.168.1.169', SignalK_UPD_PORT)) 22 | time.sleep(2) 23 | 24 | 25 | # SignalK : 26 | # environment.wind.speedApparent 27 | # environment.wind.angleApparent 28 | -------------------------------------------------------------------------------- /SignalK-tests/signalK-test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import time, socket 4 | 5 | 6 | # Initiate socket 7 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8 | # socket.AF_INET is Internet 9 | # socket.SOCK_DGRAM) is UDP 10 | # SignalK_UPD_PORT=55557 11 | SignalK_UPD_PORT=20220 12 | 13 | 14 | print("Trying to send values to SignalK") 15 | 16 | while True: 17 | t=input("Please enter a number: ") 18 | x = float(t) 19 | 20 | SignalK='{"updates": [{"$source": "OrangePi","values":[ {"path":"OrangePi.signalK.manual","value":'+format(x,'5.3f')+'}]}]}' 21 | print(SignalK) 22 | 23 | # sock.sendto(SignalK, ('192.168.1.169', 55557)) 24 | sock.sendto(SignalK, ('192.168.1.169', SignalK_UPD_PORT)) 25 | 26 | # SignalK : 27 | # environment.wind.speedApparent 28 | # environment.wind.angleApparent 29 | -------------------------------------------------------------------------------- /Winter-monitor/crontab: -------------------------------------------------------------------------------- 1 | # Edit this file to introduce tasks to be run by cron. 2 | # 3 | # Each task to run has to be defined through a single line 4 | # indicating with different fields when the task will be run 5 | # and what command to run for the task 6 | # 7 | # To define the time you can provide concrete values for 8 | # minute (m), hour (h), day of month (dom), month (mon), 9 | # and day of week (dow) or use '*' in these fields (for 'any').# 10 | # Notice that tasks will be started based on the cron's system 11 | # daemon's notion of time and timezones. 12 | # 13 | # Output of the crontab jobs (including errors) is sent through 14 | # email to the user the crontab file belongs to (unless redirected). 15 | # 16 | # For example, you can run a backup of all your user accounts 17 | # at 5 a.m every week with: 18 | # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ 19 | # 20 | # For more information see the manual pages of crontab(5) and cron(8) 21 | # 22 | # m h dom mon dow command 23 | # 24 | # Keep alive, frequent monitoring 25 | 00,15,30,45 * * * * /root/loglog.sh 26 | #13 13 * * * "service networking restart" 27 | 14 17 * * * /root/dhclient.sh 28 | # Monitoring 29 | 50 03,09,15,21 * * * /root/log.sh 30 | 20 03,09,15,21 * * * /home/ole/thingspeak/send-to-thingspeak.py 31 | # Power cycle charging 32 | 00 00 * * * /home/ole/python/pwroff.py 33 | 05 00 * * * /home/ole/python/pwron.py 34 | 00 06 * * * /home/ole/python/pwroff.py 35 | 05 06 * * * /home/ole/python/pwron.py 36 | 00 12 * * * /home/ole/python/pwroff.py 37 | 05 12 * * * /home/ole/python/pwron.py 38 | 00 18 * * * /home/ole/python/pwroff.py 39 | 05 18 * * * /home/ole/python/pwron.py 40 | 41 | -------------------------------------------------------------------------------- /Winter-monitor/dhclient.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /sbin/dhclient -r 3 | /sbin/dhclient -v 2> /root/dhclient.log 4 | 5 | -------------------------------------------------------------------------------- /Winter-monitor/log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | logdir=Yacht-computer/LOGS/ 4 | 5 | dtg=$(date +%F_%H-%M) 6 | logfile=algoldata-${dtg}.log 7 | python /home/ole/python/readtemp.py > $logfile 8 | /home/ole/python/DHT/hum.sh >> $logfile 9 | python /home/ole/python/level.py >> $logfile 10 | rsync -s $logfile ole@gina.domain.no:$logdir 11 | rm $logfile 12 | 13 | /home/ole/python/lyspaa.py 14 | sleep 1 15 | imgfile=algolimage-${dtg}.jpeg 16 | streamer -s 640x480 -o $imgfile 17 | rsync -s $imgfile ole@gina.domain.no:$logdir 18 | rm $imgfile 19 | /home/ole/python/lysav.py 20 | 21 | imgfile=algol-ute-${dtg}.jpg 22 | fswebcam -r 1280x720 -d /dev/video2 $imgfile 23 | rsync -s $imgfile ole@gina.domain.no:$logdir 24 | rm $imgfile 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Winter-monitor/pwron.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #import the library / Import des librairies 3 | from pyA20.gpio import gpio 4 | from pyA20.gpio import port 5 | from time import sleep 6 | 7 | #initialize the gpio module / initialise le GPIO 8 | gpio.init() 9 | 10 | #setup the port (same as raspberry pi's gpio.setup() function) 11 | #Configure la broche PG8 12 | gpio.setcfg(port.PG8, gpio.OUTPUT) 13 | 14 | gpio.output(port.PG8, gpio.HIGH) 15 | #gpio.output(port.PG7, gpio.LOW) 16 | 17 | -------------------------------------------------------------------------------- /Winter-monitor/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # BMP 180 sensor 4 | cd /sys/class/i2c-adapter/i2c-0/ 5 | echo "bmp180 0x77" > new_device 6 | 7 | # Set up reverse ssh 8 | autossh -N ole@gina.domain.no -R 8081:localhost:22 -C 9 | -------------------------------------------------------------------------------- /Winter-monitor/readme.md: -------------------------------------------------------------------------------- 1 | 2 | Files related to the winter monitoring. 3 | -------------------------------------------------------------------------------- /Winter-monitor/send-to-thingspeak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import glob 6 | import time 7 | import urllib2 8 | import math 9 | 10 | baseURL='http://api.thingspeak.com/update?api_key=****************' 11 | URL=baseURL 12 | base_dir = '/sys/bus/w1/devices/' 13 | sensors=glob.glob(base_dir + '28*') 14 | j=0 15 | T=[0,0,0] 16 | for sensor in sensors: 17 | sens=sensor+'/w1_slave' 18 | raw = open(sens, "r").read() 19 | T[j] = float(raw.split("t=")[-1])/1000 20 | URL=URL+'&field'+str(j+1)+'='+str(T[j]) 21 | j+=1 22 | # print(URL) 23 | 24 | #print("Temperature sensor %d : %4.1f deg C" %(j, T)) 25 | #print("%d %4.1f" %(j, T)) 26 | 27 | pressure=open("/sys/bus/i2c/drivers/bmp280/0-0077/iio:device1/in_pressure_input","r").read() 28 | # Correct for 1 m above sea level, scale height (8.314*278)/(0.029*9.82) 29 | P=float(pressure)*10.0*math.exp(1.0/8160.0) 30 | #print P,"hPa" 31 | 32 | 33 | #print("Temperature sent ",T) 34 | #print("Pressure sent ",P) 35 | 36 | #print("Humidity") 37 | dht11=" " 38 | while dht11.find("True") < 0: 39 | dht11 = os.popen('python /home/ole/python/DHT/hum.py').read() 40 | time.sleep(2) 41 | 42 | H=float(dht11[107:113]) 43 | #print(H) 44 | 45 | #print baseURL+str(T)+'&field2='+str(P)+'&field3='+str(H) 46 | 47 | # Send it to thingspeak 48 | URL=URL+'&field4='+str(H)+'&field5='+str(P) 49 | #print(URL) 50 | 51 | f = urllib2.urlopen(URL) 52 | f.read() 53 | f.close() 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /img/ADS1115-b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/ADS1115-b.jpg -------------------------------------------------------------------------------- /img/ADS1115-c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/ADS1115-c.jpg -------------------------------------------------------------------------------- /img/ADS1115-d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/ADS1115-d.jpg -------------------------------------------------------------------------------- /img/AIS-receiver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/AIS-receiver.jpg -------------------------------------------------------------------------------- /img/DSC_8967.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_8967.JPG -------------------------------------------------------------------------------- /img/DSC_8968.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_8968.JPG -------------------------------------------------------------------------------- /img/DSC_8972.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_8972.JPG -------------------------------------------------------------------------------- /img/DSC_9061.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_9061.JPG -------------------------------------------------------------------------------- /img/DSC_9063.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_9063.JPG -------------------------------------------------------------------------------- /img/DSC_9065.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_9065.JPG -------------------------------------------------------------------------------- /img/DSC_9068.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/DSC_9068.JPG -------------------------------------------------------------------------------- /img/ESP12E-I-and-U.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/ESP12E-I-and-U.jpg -------------------------------------------------------------------------------- /img/ESP8266-voltage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/ESP8266-voltage.jpg -------------------------------------------------------------------------------- /img/Hall-effect-sensors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Hall-effect-sensors.jpg -------------------------------------------------------------------------------- /img/Hall-sensor-voltage-resistors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Hall-sensor-voltage-resistors.jpg -------------------------------------------------------------------------------- /img/I2C-extender.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/I2C-extender.jpg -------------------------------------------------------------------------------- /img/MCP3008-Current-sensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/MCP3008-Current-sensor.jpg -------------------------------------------------------------------------------- /img/MCP3008-details.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/MCP3008-details.jpg -------------------------------------------------------------------------------- /img/Magnetometer-and-Gyro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Magnetometer-and-Gyro.jpg -------------------------------------------------------------------------------- /img/NTC-sensors1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/NTC-sensors1.JPG -------------------------------------------------------------------------------- /img/PFC8574.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/PFC8574.jpg -------------------------------------------------------------------------------- /img/README.md: -------------------------------------------------------------------------------- 1 | # Images related to the Yache server project 2 | -------------------------------------------------------------------------------- /img/Tank-level_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Tank-level_bb.png -------------------------------------------------------------------------------- /img/Temp-NTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Temp-NTC.png -------------------------------------------------------------------------------- /img/Temperature-NTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Temperature-NTC.png -------------------------------------------------------------------------------- /img/Temperatures_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Temperatures_bb.png -------------------------------------------------------------------------------- /img/UI-ESP32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/UI-ESP32.jpg -------------------------------------------------------------------------------- /img/Water-level-sensor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/Water-level-sensor.jpg -------------------------------------------------------------------------------- /img/kompass-gyro-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/kompass-gyro-01.jpg -------------------------------------------------------------------------------- /img/kompass-gyro-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/img/kompass-gyro-03.jpg -------------------------------------------------------------------------------- /pat/GRIB.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Function to get the position from the gpsd server. 4 | 5 | def gpsdclient(): 6 | import gps 7 | port='2947' # Port is default, seldom changed. 8 | host='localhost' # 10.10.10.1 for OpenPlotter. 9 | 10 | session = gps.gps(host=host, port=port,mode=gps.WATCH_ENABLE) 11 | while 0 == session.read() : 12 | if not (gps.MODE_SET & session.valid): 13 | # not useful, probably not a TPV message 14 | continue 15 | if ((gps.isfinite(session.fix.latitude) and 16 | gps.isfinite(session.fix.longitude))): 17 | # print(" Lat %.6f Lon %.6f" % 18 | # (session.fix.latitude, session.fix.longitude)) 19 | return session.fix.latitude, session.fix.longitude 20 | break 21 | session.close() 22 | # End gpsdclient 23 | 24 | 25 | # Main body start here. 26 | 27 | lat, lon = gpsdclient() 28 | 29 | SizeLat = 10 30 | SizeLon = 20 31 | 32 | LatL = round(lat) - SizeLat 33 | LatH = round(lat) + SizeLat 34 | LonL = round(lon) - SizeLon 35 | LonH = round(lon) + SizeLon 36 | 37 | # Lattitude : 38 | HemL = 'N' if LatL >= 0 else 'S' 39 | HemH = 'N' if LatH >= 0 else 'S' 40 | # Longitude: 41 | EWL = 'E' if LonL >= 0 else 'W' 42 | EWH = 'E' if LonH >= 0 else 'W' 43 | 44 | 45 | 46 | # ICON:50N,70N,10W,20E|1,1|0,24,48|WIND,MSLP 47 | 48 | print("{}{},{}{},{}{},{}{}".format(abs(LatL),HemL,abs(LatH),HemH,\ 49 | abs(LonL),EWL,abs(LonH),EWH)) 50 | 51 | -------------------------------------------------------------------------------- /pat/ardop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/pat/ardop.png -------------------------------------------------------------------------------- /pat/ardop.start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # change to a log dir. 5 | cd $HOME/pi/pat/log 6 | 7 | PID_ARDOP=$(pidof piardopc) 8 | if [ $? -ne 0 ]; then 9 | echo "Starting piardopc"; 10 | piardopc 8515 plughw:2,0 plughw:2,0 > piardopc.log & 11 | else 12 | echo "piardopc running"; 13 | fi 14 | PID_ARDOP_GUI=$(pidof piARDOP_GUI) 15 | if [ $? -ne 0 ]; then 16 | piARDOP_GUI & 17 | fi 18 | 19 | 20 | -------------------------------------------------------------------------------- /pat/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "mycall": "CALLSIGN", 3 | "secure_login_password": "PASSWORD", 4 | "auxiliary_addresses": [], 5 | "locator": "JO59JX", 6 | "service_codes": [ 7 | "PUBLIC" 8 | ], 9 | "http_addr": "0.0.0.0:5000", 10 | "motd": [ 11 | "Open source Winlink client - getpat.io" 12 | ], 13 | "connect_aliases": { 14 | "LA2T-160m": "vara:///LA2T?freq=1843&bw=500", 15 | "LA2T-80m": "vara:///LA2T?freq=3595.5&bw=500", 16 | "LA1T-60m": "vara:///LA1T?freq=5273&bw=2300", 17 | "telnet": "telnet://{mycall}:CMSTelnet@cms.winlink.org:8772/wl2k" 18 | }, 19 | "listen": [], 20 | "hamlib_rigs": {"G90": {"address": "localhost:4532", "network": "tcp"}}, 21 | "ax25": { 22 | "port": "wl2k", 23 | "beacon": { 24 | "every": 3600, 25 | "message": "Winlink P2P", 26 | "destination": "IDENT" 27 | }, 28 | "rig": "G90" 29 | }, 30 | "serial-tnc": { 31 | "path": "/dev/ttyUSB0", 32 | "serial_baud": 9600, 33 | "hbaud": 1200, 34 | "type": "Kenwood" 35 | }, 36 | "winmor": { 37 | "addr": "localhost:8500", 38 | "inbound_bandwidth": 1600, 39 | "drive_level": 0, 40 | "rig": "", 41 | "ptt_ctrl": false 42 | }, 43 | "ardop": { 44 | "addr": "localhost:8515", 45 | "arq_bandwidth": { 46 | "Forced": false, 47 | "Max": 2000 48 | }, 49 | "rig": "G90", 50 | "ptt_ctrl": true, 51 | "beacon_interval": 0, 52 | "cwid_enabled": true 53 | }, 54 | "vara": { 55 | "host": "localhost", 56 | "cmdPort": 8300, 57 | "dataPort": 8301, 58 | "rig": "G90", 59 | "ptt_ctrl": true 60 | }, 61 | "pactor": { 62 | "path": "/dev/ttyUSB0", 63 | "baudrate": 57600, 64 | "rig": "", 65 | "custom_init_script": "" 66 | }, 67 | "telnet": { 68 | "listen_addr": ":8774", 69 | "password": "" 70 | }, 71 | "gpsd": { 72 | "enable_http": false, 73 | "use_server_time": false, 74 | "addr": "localhost:2947" 75 | }, 76 | "schedule": {}, 77 | "version_reporting_disabled": false 78 | } 79 | -------------------------------------------------------------------------------- /pat/get-date-from-SignalK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os, json, requests 3 | 4 | # Script to set the time and date from SignalK. The RPi have no internal 5 | # real time battery powered clock to keep time. Without internet 6 | # connection it cannot set its clock. When a separate GPS is not 7 | # connected it ned to ask the SignalK server for time data. 8 | 9 | # 10 | # Setting UTC timezone via CLI : 11 | # sudo rm /etc/localtime 12 | # sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime 13 | # 14 | # timedatectl list-timezones 15 | # 16 | # UTC or Europe/Oslo 17 | # 18 | # sudo timedatectl set-timezone Europe/Oslo 19 | # sudo timedatectl set-timezone UTC 20 | # 21 | 22 | resp = requests.get('http://demo.signalk.org/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 23 | 24 | #resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 25 | 26 | 27 | data = json.loads(resp.content) 28 | print(data) 29 | #cmd="sudo date -s "+data 30 | #os.system(cmd) 31 | Y=data[0:4] 32 | M=data[5:7] 33 | D=data[8:10] 34 | h=data[11:13] 35 | m=data[14:16] 36 | s=data[17:24] 37 | print(D,"/",M,"-",Y," ",h,":",m,":",s) 38 | 39 | -------------------------------------------------------------------------------- /pat/get-weather.txt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Generating weather package request for PAT" 4 | 5 | # Each file sent as a separate request. As one chart if tens of kilobytes it's 6 | # better to split them up. 7 | # 8 | # 9 | # PPVA89.TIF Surface Analysis (North Atlantic) 10 | # PPVE89.TIF 24HR Surface Forecast (North Atlantic) 11 | # PPVI89.TIF 48HR Surface Forecast (North Atlantic) 12 | # PPVK89.TIF 72HR Surface Forecast (North Atlantic) 13 | # 14 | # ICON:50N,70N,10W,20E|1,1|0,24,48|WIND,MSLP 15 | # ECMWF:50N,70N,10W,20E|1,1|0,24,48|MSLP,WIND 16 | 17 | #for meteo in PPVA89.TIF PPVE89.TIF PPVI89.TIF \ 18 | # "ICON:40N,70N,10W,20E|0.25,0.25|0,24,48|WIND,MSLP"; do 19 | # 20 | # (echo send $meteo ) | cat 21 | # #(echo send $meteo ) | pat compose -s request query@saildocs.com 22 | #done 23 | 24 | for meteo in PPVA89.TIF PPVE89.TIF PPVI89.TIF ; do 25 | 26 | (echo send $meteo ) | cat 27 | (echo send $meteo ) | pat compose -s request query@saildocs.com 28 | done 29 | 30 | MODEL="ICON" 31 | #MODEL="ECMWF" 32 | 33 | GRIB=${MODEL}":"$(./GRIB.py)"|1,1|0,24,48|WIND,MSLP" 34 | 35 | (echo send $GRIB) | cat 36 | (echo send $GRIB) | pat compose -s request query@saildocs.com 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /pat/get.grid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Adapted, collected and edited by Ole W. Saastad, LB4PJ 4 | # 22 June 2022. 5 | 6 | # Original code from user «Sailoog» at openmarine forum. 7 | # 8 | 9 | import sys, json, requests 10 | 11 | #resp = requests.get('http://localhost:3000/signalk/v1/api/vessels/self/navigation/position/value', verify=False) 12 | resp = requests.get('http://demo.signalk.org:80/signalk/v1/api/vessels/self/navigation/position/value', verify=False) 13 | # Insert your local Signal K server name or IP number and default port 3000 14 | 15 | data = json.loads(resp.content) 16 | #print(data) 17 | #print(data['longitude']) 18 | #print(data['latitude']) 19 | 20 | 21 | # Converting to grid. 22 | # 23 | # Original code by Walter Underwood, K6WRU 24 | # 25 | # Convert latitude and longitude to Maidenhead grid locators. 26 | # 27 | # Arguments are in signed decimal latitude and longitude. For example, 28 | # the location of my QTH Palo Alto, CA is: 37.429167, -122.138056 or 29 | # in degrees, minutes, and seconds: 37° 24' 49" N 122° 6' 26" W 30 | 31 | upper = 'ABCDEFGHIJKLMNOPQRSTUVWX' 32 | lower = 'abcdefghijklmnopqrstuvwx' 33 | 34 | def to_grid(dec_lat, dec_lon): 35 | if not (-180<=dec_lon<180): 36 | sys.stderr.write('longitude must be -180<=lon<180, given %f\n'%dec_lon) 37 | sys.exit(32) 38 | if not (-90<=dec_lat<90): 39 | sys.stderr.write('latitude must be -90<=lat<90, given %f\n'%dec_lat) 40 | sys.exit(33) # can't handle north pole, sorry, [A-R] 41 | 42 | adj_lat = dec_lat + 90.0 43 | adj_lon = dec_lon + 180.0 44 | 45 | grid_lat_sq = upper[int(adj_lat/10)]; 46 | grid_lon_sq = upper[int(adj_lon/20)]; 47 | 48 | grid_lat_field = str(int(adj_lat%10)) 49 | grid_lon_field = str(int((adj_lon/2)%10)) 50 | 51 | adj_lat_remainder = (adj_lat - int(adj_lat)) * 60 52 | adj_lon_remainder = ((adj_lon) - int(adj_lon/2)*2) * 60 53 | 54 | grid_lat_subsq = lower[int(adj_lat_remainder/2.5)] 55 | grid_lon_subsq = lower[int(adj_lon_remainder/5)] 56 | 57 | return grid_lon_sq + grid_lat_sq + grid_lon_field + grid_lat_field + grid_lon_subsq + grid_lat_subsq 58 | 59 | 60 | 61 | print(to_grid(data['longitude'], (data['latitude']))) 62 | 63 | 64 | -------------------------------------------------------------------------------- /pat/gpsd.config: -------------------------------------------------------------------------------- 1 | # 2 | # File /etc/defaults/gpsd 3 | # 4 | # A config file for gpds to receive sentenced from OpenPlotter's 5 | # server which can be configured to export NMEA 183 on a set port, 6 | # in this case 10110 which is commonly used for this. 7 | # Gpsd will process this stream and provide GPS gps data to any client. 8 | # Not all GPS data, but the most needed ones like time, lat and long. 9 | # Test using : gpsmon openplotterhost:10110 10 | # 11 | # Rename this file to gpsd and place at /etc/defaults/ or 12 | # just edit the default one normally present. 13 | # 14 | # Written by Ole W. Saastad, 8/Aug/2022 15 | # 16 | 17 | # Devices gpsd should collect to at boot time. 18 | # They need to be read/writeable, either by user gpsd or the group dialout. 19 | DEVICES="" 20 | 21 | # This option receicve NMEA183 sentences from OpenPlotter server 22 | # found at the IP address and port given. The default port on gpsd is 23 | # used to make life simple. 24 | GPSD_OPTIONS="-S 2947 tcp://10.10.10.1:10110" 25 | 26 | # Automatically hot add/remove USB GPS devices via gpsdctl 27 | # No USB is used so it's safe to disble. 28 | USBAUTO="false" 29 | 30 | -------------------------------------------------------------------------------- /pat/pat-control.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import time 4 | import tkinter as tk 5 | from subprocess import check_output, CalledProcessError 6 | 7 | 8 | def check_pid(name): 9 | try: 10 | p = check_output(["pidof",name]).split() 11 | except CalledProcessError: 12 | p = str(0) 13 | return p 14 | 15 | 16 | def start_pat(): 17 | for r in 1,2,3 : 18 | tk.Label(master, text=" ",anchor="e").grid(row=r) 19 | tk.Label(master, text="Starting Pat",anchor="e").grid(row=0) 20 | os.system("/home/pi/pat/pat.start") 21 | time.sleep(3) 22 | display_pids() 23 | 24 | 25 | def stop_pat(): 26 | for r in 1,2,3 : 27 | tk.Label(master, text=" ",anchor="e").grid(row=r) 28 | tk.Label(master, text="Stopping Pat",anchor="e").grid(row=0) 29 | os.system("/home/pi/pat/pat.stop") 30 | display_pids() 31 | 32 | 33 | def display_pids(): 34 | tk.Label(master, text="Services PIDs",anchor="e").grid(row=0) 35 | tk.Label(master, text="pid rigctl ").grid(row=1) 36 | tk.Label(master, text="pid piardopc ").grid(row=2) 37 | tk.Label(master, text="pid pat ").grid(row=3) 38 | e1 = tk.Entry(master, width="7") 39 | e2 = tk.Entry(master, width="7") 40 | e3 = tk.Entry(master, width="7") 41 | e1.insert(0, check_pid("rigctld")) 42 | e2.insert(0, check_pid("piardopc")) 43 | e3.insert(0, check_pid("pat")) 44 | e1.grid(row=1, column=1) 45 | e2.grid(row=2, column=1) 46 | e3.grid(row=3, column=1) 47 | 48 | 49 | 50 | master = tk.Tk() 51 | master.title("Simple Pat control") 52 | 53 | tk.Button(master, text='Start', height="2", 54 | command=start_pat).grid(row=4, column=0, sticky=tk.W, pady=1) 55 | 56 | tk.Button(master, text='Stop', height="2", 57 | command=stop_pat).grid(row=4, column=1, sticky=tk.W, pady=1) 58 | 59 | tk.Button(master, text='Show pids', height="2", 60 | command=display_pids).grid(row=4, column=2, sticky=tk.W, pady=1) 61 | 62 | tk.Button(master, text='Quit', height="2", 63 | command=master.quit).grid(row=4, column=3, sticky=tk.W, pady=1) 64 | 65 | 66 | master.mainloop() 67 | 68 | 69 | -------------------------------------------------------------------------------- /pat/pat-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/pat/pat-stop.png -------------------------------------------------------------------------------- /pat/pat.ardrop.start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # change to a log dir. 5 | cd $HOME/pi/pat/log 6 | 7 | # Start flrig if not running 8 | PID_FLRIG=$(pidof flrig) 9 | if [ $? -ne 0 ]; then 10 | echo "Flrig not running, starting flrig." 11 | flrig & 12 | sleep 2 13 | PID_FLRIG=$(pidof flrig) 14 | if [ $? -ne 0 ]; then 15 | exit; 16 | fi 17 | fi 18 | sleep 2; 19 | 20 | # Start rigctl deamon -m 4 (4 is flrig). 21 | PID_FLRIG=$(pidof rigctld) 22 | if [ $? -ne 0 ]; then 23 | echo "Starting rigctld deamon"; 24 | rigctl -m 4 M USB 2400 25 | rigctld -m 4 > rigctld.log & 26 | fi 27 | 28 | PID_ARDOP=$(pidof piardopc) 29 | if [ $? -ne 0 ]; then 30 | echo "Starting piardopc"; 31 | piardopc 8515 plughw:2,0 plughw:2,0 > piardopc.log & 32 | else 33 | echo "piardopc running"; 34 | fi 35 | PID_ARDOP_GUI=$(pidof piARDOP_GUI) 36 | if [ $? -ne 0 ]; then 37 | piARDOP_GUI & 38 | fi 39 | 40 | 41 | 42 | PID_PAT=$(pidof pat) 43 | if [ $? -ne 0 ]; then 44 | echo "Staring Pat" 45 | pat http > pat.log & 46 | else 47 | echo "pat running" 48 | fi 49 | 50 | 51 | -------------------------------------------------------------------------------- /pat/pat.pid: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for app in pat piardopc rigctld ; do 4 | #echo $app 5 | p=$(pidof $app); 6 | if [ $? -eq 0 ]; then 7 | echo "PID of " $app $p 8 | else 9 | echo $app "not running" 10 | fi 11 | done -------------------------------------------------------------------------------- /pat/pat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/pat/pat.png -------------------------------------------------------------------------------- /pat/pat.start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # change to a log dir. 5 | cd $HOME/pi/pat/log 6 | 7 | # Start flrig if not running 8 | PID_FLRIG=$(pidof flrig) 9 | if [ $? -ne 0 ]; then 10 | echo "Flrig not running, starting flrig." 11 | flrig & 12 | sleep 2 13 | PID_FLRIG=$(pidof flrig) 14 | if [ $? -ne 0 ]; then 15 | exit; 16 | fi 17 | fi 18 | sleep 2; 19 | 20 | # Start rigctl deamon -m 4 (4 is flrig). 21 | PID_FLRIG=$(pidof rigctld) 22 | if [ $? -ne 0 ]; then 23 | echo "Starting rigctld deamon"; 24 | rigctl -m 4 M USB 2400 25 | rigctld -m 4 > rigctld.log & 26 | fi 27 | 28 | PID_ARDOP=$(pidof piardopc) 29 | if [ $? -ne 0 ]; then 30 | echo "Starting piardopc"; 31 | piardopc 8515 plughw:2,0 plughw:2,0 > piardopc.log & 32 | else 33 | echo "piardopc running"; 34 | fi 35 | PID_ARDOP_GUI=$(pidof piARDOP_GUI) 36 | if [ $? -ne 0 ]; then 37 | piARDOP_GUI & 38 | fi 39 | 40 | 41 | 42 | PID_PAT=$(pidof pat) 43 | if [ $? -ne 0 ]; then 44 | echo "Staring Pat" 45 | pat http > pat.log & 46 | else 47 | echo "pat running" 48 | fi 49 | 50 | 51 | -------------------------------------------------------------------------------- /pat/pat.stop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | killall pat 4 | killall piardopc 5 | killall rigctld 6 | killall piARDOP_GUI 7 | 8 | pidof pat 9 | pidof piardopc 10 | pidof rigctld 11 | pidof piARDOP_GUI 12 | 13 | 14 | -------------------------------------------------------------------------------- /pat/pat.vara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/olewsaa/Yacht-computer/f84f85d8dde31a291430c8c7734633196d824555/pat/pat.vara.png -------------------------------------------------------------------------------- /pat/pat.vara.start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # change to a log dir. 5 | cd $HOME/pi/pat/log 6 | 7 | # Start flrig if not running 8 | PID_FLRIG=$(pidof flrig) 9 | if [ $? -ne 0 ]; then 10 | echo "Flrig not running, starting flrig." 11 | flrig & 12 | sleep 2 13 | PID_FLRIG=$(pidof flrig) 14 | if [ $? -ne 0 ]; then 15 | exit; 16 | fi 17 | fi 18 | sleep 2; 19 | 20 | # Start rigctl deamon -m 4 (4 is flrig). 21 | PID_FLRIG=$(pidof rigctld) 22 | if [ $? -ne 0 ]; then 23 | echo "Starting rigctld deamon"; 24 | rigctl -m 4 M USB 2400 25 | rigctld -m 4 > rigctld.log & 26 | fi 27 | 28 | #PID_ARDOP=$(pidof piardopc) 29 | #if [ $? -ne 0 ]; then 30 | # echo "Starting piardopc"; 31 | # piardopc 8515 plughw:2,0 plughw:2,0 > piardopc.log & 32 | #else 33 | # echo "piardopc running"; 34 | #fi 35 | #PID_ARDOP_GUI=$(pidof piARDOP_GUI) 36 | #if [ $? -ne 0 ]; then 37 | # piARDOP_GUI & 38 | #fi 39 | 40 | 41 | 42 | PID_PAT=$(pidof pat) 43 | if [ $? -ne 0 ]; then 44 | echo "Staring Pat" 45 | pat http > pat.log & 46 | else 47 | echo "pat running" 48 | fi 49 | 50 | 51 | -------------------------------------------------------------------------------- /pat/set-date-from-SignalK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os, json, requests 3 | 4 | # Script to set the time and date from SignalK. The RPi have no internal 5 | # real time battery powered clock to keep time. Without internet 6 | # connection it cannot set its clock. When a separate GPS is not 7 | # connected it ned to ask the SignalK server for time data. 8 | # 9 | # 10 | # Setting UTC timezone via CLI : 11 | # sudo rm /etc/localtime 12 | # sudo ln -s /usr/share/zoneinfo/UTC /etc/localtime 13 | # 14 | # timedatectl list-timezones 15 | # 16 | # UTC or Europe/Oslo 17 | # 18 | # sudo timedatectl set-timezone Europe/Oslo 19 | # sudo timedatectl set-timezone UTC 20 | # 21 | 22 | NTPrunning=os.system('ntpstat>/dev/null') 23 | #print("NTP status", NTPrunning) 24 | if (NTPrunning != 0): 25 | resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False)a 26 | 27 | #resp = requests.get('http://demo.signalk.org/signalk/v1/api/vessels/self/navigation/datetime/value', verify=False) 28 | 29 | #print(resp) 30 | data = json.loads(resp.content) 31 | #print(data) 32 | cmd="sudo date -s "+data 33 | #print(cmd) 34 | os.system(cmd) 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /pat/showpos.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Python script to collect the current GPS position from 5 | # Signal K and display it. 6 | # 7 | # Adapted, collected and edited by Ole W. Saastad, LB4PJ 8 | # 23 June 2022. 9 | # 14 July 2022 Added check for valid SignalK response 10 | # 08 August 2022 Changed to only displaying position 11 | 12 | # Original code to request from Signal K - from user «Sailoog» at 13 | # openmarine forum. 14 | 15 | import sys, json, requests 16 | 17 | resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/position/value', verify=False) 18 | # Insert your local Signal K server name or IP number and default port 3000 19 | if (resp.status_code == 404): 20 | exit(1) 21 | # Just exit if no valid response from the SignalK server. 22 | 23 | data = json.loads(resp.content) 24 | 25 | # 26 | # Converting to grid, original code by Walter Underwood, K6WRU 27 | # 28 | # Convert latitude and longitude to Maidenhead grid locators. 29 | # 30 | # Arguments are in signed decimal latitude and longitude. For example, 31 | # the location of my QTH Palo Alto, CA is: 37.429167, -122.138056 or 32 | # in degrees, minutes, and seconds: 37° 24' 49" N 122° 6' 26" W 33 | 34 | upper = 'ABCDEFGHIJKLMNOPQRSTUVWX' 35 | lower = 'abcdefghijklmnopqrstuvwx' 36 | 37 | def to_grid(dec_lat, dec_lon): 38 | if not (-180<=dec_lon<180): 39 | sys.stderr.write('longitude must be -180<=lon<180, given %f\n'%dec_lon) 40 | sys.exit(32) 41 | if not (-90<=dec_lat<90): 42 | sys.stderr.write('latitude must be -90<=lat<90, given %f\n'%dec_lat) 43 | sys.exit(33) # can't handle north pole, sorry, [A-R] 44 | 45 | adj_lat = dec_lat + 90.0 46 | adj_lon = dec_lon + 180.0 47 | 48 | grid_lat_sq = upper[int(adj_lat/10)]; 49 | grid_lon_sq = upper[int(adj_lon/20)]; 50 | 51 | grid_lat_field = str(int(adj_lat%10)) 52 | grid_lon_field = str(int((adj_lon/2)%10)) 53 | 54 | adj_lat_remainder = (adj_lat - int(adj_lat)) * 60 55 | adj_lon_remainder = ((adj_lon) - int(adj_lon/2)*2) * 60 56 | 57 | grid_lat_subsq = lower[int(adj_lat_remainder/2.5)] 58 | grid_lon_subsq = lower[int(adj_lon_remainder/5)] 59 | 60 | return grid_lon_sq + grid_lat_sq + grid_lon_field + grid_lat_field + grid_lon_subsq + grid_lat_subsq 61 | 62 | 63 | #print(data['latitude'], data['longitude']) 64 | 65 | 66 | # Main start here. 67 | 68 | print(data['latitude']) 69 | print(data['longitude']) 70 | 71 | grid=to_grid(float(data['latitude']), float((data['longitude']))) 72 | print(grid) 73 | 74 | # end main 75 | 76 | -------------------------------------------------------------------------------- /pat/update.pos.pat.conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Python script to collect the current GPS position from 5 | # Signal K and use it to update the 'locator' variable 6 | # in the pat configure file. Causing current location to 7 | # be used each time pat is started. 8 | # 9 | # Adapted, collected and edited by Ole W. Saastad, LB4PJ 10 | # 23 June 2022. 11 | # 14 July 2022 Added check for valid SignalK response 12 | # 13 | 14 | # Original code to request from Signal K - from user «Sailoog» at 15 | # openmarine forum. 16 | 17 | import sys, json, requests 18 | 19 | #resp = requests.get('http://localhost:3000/signalk/v1/api/vessels/self/navigation/position/value', verify=False) 20 | resp = requests.get('http://10.10.10.1:3000/signalk/v1/api/vessels/self/navigation/position/value', verify=False) 21 | # Insert your local Signal K server name or IP number and default port 3000 22 | if (resp.status_code == 404): 23 | exit(1) 24 | # Just exit if no valid response from the SignalK server. 25 | 26 | data = json.loads(resp.content) 27 | #print(data) 28 | #print(data['longitude']) 29 | #print(data['latitude']) 30 | 31 | 32 | 33 | # 34 | # Converting to grid, original code by Walter Underwood, K6WRU 35 | # 36 | # Convert latitude and longitude to Maidenhead grid locators. 37 | # 38 | # Arguments are in signed decimal latitude and longitude. For example, 39 | # the location of my QTH Palo Alto, CA is: 37.429167, -122.138056 or 40 | # in degrees, minutes, and seconds: 37° 24' 49" N 122° 6' 26" W 41 | 42 | upper = 'ABCDEFGHIJKLMNOPQRSTUVWX' 43 | lower = 'abcdefghijklmnopqrstuvwx' 44 | 45 | def to_grid(dec_lat, dec_lon): 46 | if not (-180<=dec_lon<180): 47 | sys.stderr.write('longitude must be -180<=lon<180, given %f\n'%dec_lon) 48 | sys.exit(32) 49 | if not (-90<=dec_lat<90): 50 | sys.stderr.write('latitude must be -90<=lat<90, given %f\n'%dec_lat) 51 | sys.exit(33) # can't handle north pole, sorry, [A-R] 52 | 53 | adj_lat = dec_lat + 90.0 54 | adj_lon = dec_lon + 180.0 55 | 56 | grid_lat_sq = upper[int(adj_lat/10)]; 57 | grid_lon_sq = upper[int(adj_lon/20)]; 58 | 59 | grid_lat_field = str(int(adj_lat%10)) 60 | grid_lon_field = str(int((adj_lon/2)%10)) 61 | 62 | adj_lat_remainder = (adj_lat - int(adj_lat)) * 60 63 | adj_lon_remainder = ((adj_lon) - int(adj_lon/2)*2) * 60 64 | 65 | grid_lat_subsq = lower[int(adj_lat_remainder/2.5)] 66 | grid_lon_subsq = lower[int(adj_lon_remainder/5)] 67 | 68 | return grid_lon_sq + grid_lat_sq + grid_lon_field + grid_lat_field + grid_lon_subsq + grid_lat_subsq 69 | 70 | #print(data['latitude'], data['longitude']) 71 | 72 | grid=to_grid(float(data['latitude']), float((data['longitude']))) 73 | #print(grid) 74 | 75 | 76 | # Main start here. 77 | 78 | # Update the pat config file, a quick fix so that each time pat 79 | # started the position is updated. Put this file in the pat launch 80 | # script before pat is launched and pat will start with the current 81 | # position. 82 | 83 | # /home/pi/.config/pat/config.json 84 | cf="/home/pi/.config/pat/config.json" 85 | f=open(cf,"r+") 86 | config = json.load(f) 87 | config['locator']=to_grid(data['latitude'], (data['longitude'])) 88 | json_obj=json.dumps(config, indent=4) 89 | f.truncate(0) # Clear the file 90 | f.seek(0) # I miss the rewind statement. 91 | f.write(json_obj) 92 | f.close() 93 | 94 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/dhcpcd.conf: -------------------------------------------------------------------------------- 1 | # A sample configuration for dhcpcd. 2 | # See dhcpcd.conf(5) for details. 3 | 4 | # Allow users of this group to interact with dhcpcd via the control socket. 5 | #controlgroup wheel 6 | 7 | # Inform the DHCP server of our hostname for DDNS. 8 | hostname 9 | 10 | # Use the hardware address of the interface for the Client ID. 11 | clientid 12 | # or 13 | # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. 14 | # Some non-RFC compliant DHCP servers do not reply with this set. 15 | # In this case, comment out duid and enable clientid above. 16 | #duid 17 | 18 | # Persist interface configuration when dhcpcd exits. 19 | persistent 20 | 21 | # Rapid commit support. 22 | # Safe to enable by default because it requires the equivalent option set 23 | # on the server to actually work. 24 | option rapid_commit 25 | 26 | # A list of options to request from the DHCP server. 27 | option domain_name_servers, domain_name, domain_search, host_name 28 | option classless_static_routes 29 | # Most distributions have NTP support. 30 | option ntp_servers 31 | # Respect the network MTU. This is applied to DHCP routes. 32 | option interface_mtu 33 | 34 | # A ServerID is required by RFC2131. 35 | require dhcp_server_identifier 36 | 37 | # Generate Stable Private IPv6 Addresses instead of hardware based ones 38 | slaac private 39 | 40 | # Example static IP configuration: 41 | #interface eth0 42 | #static ip_address=192.168.0.10/24 43 | #static ip6_address=fd51:42f8:caae:d92e::ff/64 44 | #static routers=192.168.0.1 45 | #static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1 46 | 47 | # It is possible to fall back to a static IP if DHCP fails: 48 | # define static profile 49 | #profile static_eth0 50 | #static ip_address=192.168.1.23/24 51 | #static routers=192.168.1.1 52 | #static domain_name_servers=192.168.1.1 53 | 54 | # fallback to static profile on eth0 55 | #interface eth0 56 | #fallback static_eth0 57 | 58 | interface eth0 59 | static ip_address=172.16.10.10/24 60 | denyinterfaces wlan0 61 | denyinterfaces wlan1 62 | static routers= 63 | static domain_name_servers= 64 | static domain_search= 65 | 66 | interface wlan0 67 | static ip_address=192.168.0.10/24 68 | denyinterfaces wlan1 69 | denyinterfaces eth0 70 | static routers= 71 | static domain_name_servers= 72 | static domain_search= 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/dnsmasq.conf: -------------------------------------------------------------------------------- 1 | interface=wlan0 2 | dhcp-range=192.168.0.11,192.168.0.30,255.255.255.0,24h 3 | 4 | interface=eth0 5 | dhcp-range=172.16.10.11,172.16.10.30,255.255.255.0,24h 6 | 7 | dhcp-host=greybox,192.168.0.10 8 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/hostapd: -------------------------------------------------------------------------------- 1 | # Defaults for hostapd initscript 2 | # 3 | # See /usr/share/doc/hostapd/README.Debian for information about alternative 4 | # methods of managing hostapd. 5 | # 6 | # Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration 7 | # file and hostapd will be started during system boot. An example configuration 8 | # file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz 9 | # 10 | DAEMON_CONF="/etc/hostapd/hostapd.conf" 11 | 12 | # Additional daemon options to be appended to hostapd command:- 13 | # -d show more debug messages (-dd for even more) 14 | # -K include key data in debug messages 15 | # -t include timestamps in some debug messages 16 | # 17 | # Note that -B (daemon mode) and -P (pidfile) options are automatically 18 | # configured by the init.d script and must not be added to DAEMON_OPTS. 19 | # 20 | #DAEMON_OPTS="" 21 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/hostapd.conf: -------------------------------------------------------------------------------- 1 | interface=wlan0 2 | hw_mode=g 3 | channel=3 4 | wmm_enabled=0 5 | macaddr_acl=0 6 | auth_algs=1 7 | ignore_broadcast_ssid=0 8 | wpa=2 9 | wpa_key_mgmt=WPA-PSK 10 | wpa_pairwise=TKIP 11 | rsn_pairwise=CCMP 12 | ssid=algol 13 | wpa_passphrase=blackpearl 14 | 15 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/hosts: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | ::1 localhost ip6-localhost ip6-loopback 3 | ff02::1 ip6-allnodes 4 | ff02::2 ip6-allrouters 5 | 6 | 127.0.1.1 raspberrypi 7 | 192.168.0.10 greybox 8 | 9 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/interfaces: -------------------------------------------------------------------------------- 1 | # interfaces(5) file used by ifup(8) and ifdown(8) 2 | 3 | # Please note that this file is written to be used with dhcpcd 4 | # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf' 5 | 6 | # Include files from /etc/network/interfaces.d: 7 | source-directory /etc/network/interfaces.d 8 | 9 | 10 | allow-hotplug wlan1 11 | iface wlan1 inet dhcp 12 | wpa-conf /etc/wpa_supplicant/wpa_supplicant1.conf 13 | 14 | auto wlan0 15 | iface wlan0 inet manual 16 | hwaddress ether b8:27:eb:05:89:ec 17 | wpa-conf /etc/wpa_supplicant/wpa_supplicant0.conf 18 | 19 | 20 | auto eth0 21 | iface eth0 inet manual 22 | hwaddress ether b8:27:eb:50:dc:b9 23 | 24 | 25 | #allow-hotplug wlan0 26 | #iface wlan0 inet dhcp 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/iptables.ipv4.nat: -------------------------------------------------------------------------------- 1 | # Generated by iptables-save v1.6.0 on Mon Dec 17 13:50:20 2018 2 | *nat 3 | :PREROUTING ACCEPT [1611:236622] 4 | :INPUT ACCEPT [415:59567] 5 | :OUTPUT ACCEPT [343:59843] 6 | :POSTROUTING ACCEPT [419:49095] 7 | -A POSTROUTING -o wlan1 -j MASQUERADE 8 | COMMIT 9 | # Completed on Mon Dec 17 13:50:20 2018 10 | # Generated by iptables-save v1.6.0 on Mon Dec 17 13:50:20 2018 11 | *filter 12 | :INPUT ACCEPT [4450:451663] 13 | :FORWARD ACCEPT [1337:98290] 14 | :OUTPUT ACCEPT [3839:438247] 15 | -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 16 | -A FORWARD -i wlan0 -o wlan1 -j ACCEPT 17 | COMMIT 18 | # Completed on Mon Dec 17 13:50:20 2018 19 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # rc.local 4 | # 5 | # This script is executed at the end of each multiuser runlevel. 6 | # Make sure that the script will "exit 0" on success or any other 7 | # value on error. 8 | # 9 | # In order to enable or disable this script just change the execution 10 | # bits. 11 | # 12 | # By default this script does nothing. 13 | 14 | # Print the IP address 15 | _IP=$(hostname -I) || true 16 | if [ "$_IP" ]; then 17 | printf "My IP address is %s\n" "$_IP" 18 | fi 19 | 20 | sleep 7 21 | fbcp & 22 | 23 | 24 | iptables-restore < /etc/iptables.ipv4.nat 25 | 26 | dhcpcd -q -d -b 27 | 28 | 29 | exit 0 30 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/scan.py: -------------------------------------------------------------------------------- 1 | # 2 | # A simple script to explore text command lines to scan and connect to access points. 3 | # 4 | # 5 | 6 | import os 7 | import subprocess 8 | import time 9 | 10 | c={} 11 | print("Scanning wifi access points....") 12 | p=subprocess.check_output('wpa_cli -i wlan1 scan', shell=True) 13 | for i in range(2): 14 | time.sleep(1) 15 | print(".",end="", flush=True) 16 | print() 17 | a=subprocess.check_output('wpa_cli -i wlan1 scan_results', shell=True) 18 | b=a.splitlines(True) 19 | 20 | for i in range(len(b)): 21 | c[i]=b[i].split() 22 | 23 | for i in range(1,len(b)): 24 | if len(c[i])>4: 25 | ap_name=str(c[i][4]).replace("b'","'").replace("'","") 26 | ap_signal=-1200/int(str(c[i][2]).replace("b'","'").replace("'","")) 27 | # print(i-1,str(c[i][4]).replace("b'","'").replace("'",""),'\t',\ 28 | # (-1/int(str(c[i][2]).replace("b'","'").replace("'","")))*100) 29 | print(i-1,ap_name, "%.2f" % ap_signal) 30 | 31 | 32 | print("") 33 | p=subprocess.check_output('wpa_cli -i wlan1 list_networks', shell=True) 34 | b=p.splitlines(True) 35 | for i in range(len(b)): 36 | c[i]=b[i].split() 37 | #print(c[i]) 38 | if (len(c[i])>3): 39 | if (str(c[i][3]).find("CURRENT")==3): 40 | print("Active network is : ",\ 41 | str(c[i][1]).replace("b'","'").replace("'","")) 42 | 43 | 44 | 45 | name=input("Connect to network >") 46 | p=subprocess.check_output('wpa_cli -i wlan1 list_networks', shell=True) 47 | print(p) 48 | if (str(p).find(name)>0): 49 | print("known") 50 | b=p.splitlines(True) 51 | for j in range(1,len(b)): 52 | #print(b[j],type(b[j])) 53 | #print(str(b[j]).find(name)) 54 | if str(b[j]).find(name)>0: 55 | line=b[j].split() 56 | #line=str(p.splitlines()[0]).replace("b'","").replace("'","") 57 | #print(str(line[0]).replace("b'","").replace("'","")) 58 | no=(str(line[0]).replace("b'","").replace("'","")) 59 | print("Number ", no) 60 | else: 61 | pw=input("Password >") 62 | print("Trying to connect to :",name) 63 | p=subprocess.check_output('wpa_cli -i wlan1 add_network', shell=True) 64 | no=int(str(p.splitlines()[0]).replace("b'","").replace("'","")) 65 | cmd="wpa_cli -i wlan1 set_network "+str(no)+" ssid "+"'\""+name+"\"'" 66 | p=subprocess.check_output(cmd, shell=True) 67 | if str(p).find("OK")<0: 68 | print("Failed on setting network name, exit") 69 | exit() 70 | for j in range(4): 71 | cmd="wpa_cli -i wlan1 set_network "+str(no)+" psk "+"'\""+pw+"\"'" 72 | p=subprocess.check_output(cmd, shell=True) 73 | if str(p).find("OK")<0: 74 | print("Failed on setting network password") 75 | pw=input("Password >") 76 | else: 77 | print("Password ok") 78 | p=subprocess.check_output('wpa_cli -i wlan1 save_config', shell=True) 79 | break 80 | 81 | 82 | 83 | cmd="wpa_cli -i wlan1 disconnect" 84 | print(cmd) 85 | time.sleep(5) 86 | p=subprocess.check_output(cmd, shell=True) 87 | cmd="wpa_cli -i wlan1 enable_network "+str(no) 88 | print(cmd) 89 | time.sleep(3) 90 | p=subprocess.check_output(cmd, shell=True) 91 | cmd="wpa_cli -i wlan1 reconnect" 92 | print(cmd) 93 | p=subprocess.check_output(cmd, shell=True) 94 | 95 | 96 | time.sleep(5) 97 | p=subprocess.check_output('ifconfig wlan1', shell=True) 98 | while str(p).find("broadcast")<0: 99 | time.sleep(1) 100 | print(".",end="", flush=True) 101 | p=subprocess.check_output('ifconfig wlan1', shell=True) 102 | print() 103 | b=p.splitlines(True) 104 | c=str(b[1]).split() 105 | ip=c[2].replace("b'","'").replace("'","") 106 | print("Assigned ip number on network ",name," is ",ip) 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /wifi2wifi/touch-screen-version/sysctl.conf: -------------------------------------------------------------------------------- 1 | # 2 | # /etc/sysctl.conf - Configuration file for setting system variables 3 | # See /etc/sysctl.d/ for additional system variables. 4 | # See sysctl.conf (5) for information. 5 | # 6 | 7 | #kernel.domainname = example.com 8 | 9 | # Uncomment the following to stop low-level messages on console 10 | #kernel.printk = 3 4 1 3 11 | 12 | ##############################################################3 13 | # Functions previously found in netbase 14 | # 15 | 16 | # Uncomment the next two lines to enable Spoof protection (reverse-path filter) 17 | # Turn on Source Address Verification in all interfaces to 18 | # prevent some spoofing attacks 19 | #net.ipv4.conf.default.rp_filter=1 20 | #net.ipv4.conf.all.rp_filter=1 21 | 22 | # Uncomment the next line to enable TCP/IP SYN cookies 23 | # See http://lwn.net/Articles/277146/ 24 | # Note: This may impact IPv6 TCP sessions too 25 | #net.ipv4.tcp_syncookies=1 26 | 27 | # Uncomment the next line to enable packet forwarding for IPv4 28 | net.ipv4.ip_forward=1 29 | 30 | # Uncomment the next line to enable packet forwarding for IPv6 31 | # Enabling this option disables Stateless Address Autoconfiguration 32 | # based on Router Advertisements for this host 33 | #net.ipv6.conf.all.forwarding=1 34 | 35 | 36 | ################################################################### 37 | # Additional settings - these settings can improve the network 38 | # security of the host and prevent against some network attacks 39 | # including spoofing attacks and man in the middle attacks through 40 | # redirection. Some network environments, however, require that these 41 | # settings are disabled so review and enable them as needed. 42 | # 43 | # Do not accept ICMP redirects (prevent MITM attacks) 44 | #net.ipv4.conf.all.accept_redirects = 0 45 | #net.ipv6.conf.all.accept_redirects = 0 46 | # _or_ 47 | # Accept ICMP redirects only for gateways listed in our default 48 | # gateway list (enabled by default) 49 | # net.ipv4.conf.all.secure_redirects = 1 50 | # 51 | # Do not send ICMP redirects (we are not a router) 52 | #net.ipv4.conf.all.send_redirects = 0 53 | # 54 | # Do not accept IP source route packets (we are not a router) 55 | #net.ipv4.conf.all.accept_source_route = 0 56 | #net.ipv6.conf.all.accept_source_route = 0 57 | # 58 | # Log Martian Packets 59 | #net.ipv4.conf.all.log_martians = 1 60 | # 61 | 62 | ################################################################### 63 | # Magic system request Key 64 | # 0=disable, 1=enable all 65 | # Debian kernels have this set to 0 (disable the key) 66 | # See https://www.kernel.org/doc/Documentation/sysrq.txt 67 | # for what other values do 68 | #kernel.sysrq=1 69 | 70 | ################################################################### 71 | # Protected links 72 | # 73 | # Protects against creating or following links under certain conditions 74 | # Debian kernels have both set to 1 (restricted) 75 | # See https://www.kernel.org/doc/Documentation/sysctl/fs.txt 76 | #fs.protected_hardlinks=0 77 | #fs.protected_symlinks=0 78 | -------------------------------------------------------------------------------- /wifi2wifi/web-version/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Wifi 2 wifi gateway using long range USB antenna 3 | 4 | 5 | ## Wifi is desperately needed 6 | 7 | While we are waiting for Starlink to become operational we have 8 | limited acces to the internet on board while en-route. Hence the 9 | demand for access is very high when getting to place where such luxury 10 | is offered. Crew and skippers flock to the bars and cafes in the 11 | marinas as free wifi is an excellent way to attact customers. It is 12 | nice to have a long range antenna onboard to pick up these signals and 13 | hence have wifi onboard. 14 | 15 | ### Wifi gateway 16 | 17 | A wifi 2 wifi gateway using a Raspberry Pi and a long range USB high 18 | gain antenna to provide local wifi coverage onboard is a must when 19 | cruising. In addition it should be easy to use, any member of the crew 20 | should ba able to select a shore station. They comes in all variants, 21 | sometimes a code is posted and some times you'll need a reciept to get 22 | the code etc etc the list is endless. On common fact is that they 23 | generally do not offer connection below deck. Using a high gain 24 | antenna outside to pick up the signal from a marina or a café and get 25 | a reliable connection and then provide this connection to a local wifi 26 | (cable also) segment onboard is a nice way of solving this 27 | chellenge. While commercial solution do exsists (like Redbox), they 28 | are generally expensive and bundled with a lot of other functions not 29 | needed for this purpose. 30 | 31 | ## Changes in the default raspap-webgui setup 32 | 33 | This setup is based on the raspap-webgui, https://raspap.com/ project. 34 | Install according to instructions and when everything is set up and 35 | working some changes can be applied. First of all the changes to use a 36 | USB long range antenna as the WAN (Wide Area Network, aka the 37 | "internet") is needed. This is described in the FAQ section. Using 38 | wan1 as WAN connection. 39 | 40 | For most users who do not need internet access via the cable 41 | connection this is all you need. 42 | 43 | ## Limiting the access to setup in the GUI 44 | 45 | Users should only be allowed to scan for and change the shore station, 46 | not mess up the settings. This is solved by selecting monitoring in 47 | the config file. This setting is a FAQ entry in the raspiap pages. It 48 | works fine, users can log in with admin/pw and will only have access 49 | to configure the client. 50 | 51 | ## Changes to get eth0 working as Access point with dhcp 52 | 53 | The files 54 | * /etc/dhcpcd.conf 55 | * /etc/dnsmasq.conf 56 | * /etc/network/interfaces 57 | * /var/www/html/includes/config.php 58 | * /etc/hostapd/hostapd.conf 59 | 60 | need to be updated, only the extra lines 61 | to be added are included in the files listed here. You cannot copy 62 | these files, it will not work, you need to edit them. Remember to 63 | change the MAC adresses to fit your system, use the command ifconfig 64 | to list them. After the changes have been applied a reboot is 65 | needed. Things should now work with internet access available for 66 | both cabled connected devices and wifi connected devices. 67 | 68 | To safeguard against unwanted updates I have marked all these files read-only. 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /wifi2wifi/web-version/config.php: -------------------------------------------------------------------------------- 1 |