Merge pull request 'feature/backend' (#4) from feature/backend into main
Reviewed-on: #4
This commit is contained in:
		
							
								
								
									
										115
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										115
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,115 +0,0 @@ | ||||
| # ---> esp-idf | ||||
| # gitignore template for esp-idf, the official development framework for ESP32 | ||||
| # https://github.com/espressif/esp-idf | ||||
|  | ||||
| build/ | ||||
| sdkconfig | ||||
| sdkconfig.old | ||||
|  | ||||
| # ---> VisualStudioCode | ||||
| .vscode/* | ||||
| !.vscode/settings.json | ||||
| !.vscode/tasks.json | ||||
| !.vscode/launch.json | ||||
| !.vscode/extensions.json | ||||
| !.vscode/*.code-snippets | ||||
|  | ||||
| # Local History for Visual Studio Code | ||||
| .history/ | ||||
|  | ||||
| # Built Visual Studio Code Extensions | ||||
| *.vsix | ||||
|  | ||||
| # ---> Kate | ||||
| # Swap Files # | ||||
| .*.kate-swp | ||||
| .swp.* | ||||
|  | ||||
| # ---> C | ||||
| # Prerequisites | ||||
| *.d | ||||
|  | ||||
| # Object files | ||||
| *.o | ||||
| *.ko | ||||
| *.obj | ||||
| *.elf | ||||
|  | ||||
| # Linker output | ||||
| *.ilk | ||||
| *.map | ||||
| *.exp | ||||
|  | ||||
| # Precompiled Headers | ||||
| *.gch | ||||
| *.pch | ||||
|  | ||||
| # Libraries | ||||
| *.lib | ||||
| *.a | ||||
| *.la | ||||
| *.lo | ||||
|  | ||||
| # Shared objects (inc. Windows DLLs) | ||||
| *.dll | ||||
| *.so | ||||
| *.so.* | ||||
| *.dylib | ||||
|  | ||||
| # Executables | ||||
| *.exe | ||||
| *.out | ||||
| *.app | ||||
| *.i*86 | ||||
| *.x86_64 | ||||
| *.hex | ||||
|  | ||||
| # Debug files | ||||
| *.dSYM/ | ||||
| *.su | ||||
| *.idb | ||||
| *.pdb | ||||
|  | ||||
| # Kernel Module Compile Results | ||||
| *.mod* | ||||
| *.cmd | ||||
| .tmp_versions/ | ||||
| modules.order | ||||
| Module.symvers | ||||
| Mkfile.old | ||||
| dkms.conf | ||||
|  | ||||
| # ---> C++ | ||||
| # Prerequisites | ||||
| *.d | ||||
|  | ||||
| # Compiled Object files | ||||
| *.slo | ||||
| *.lo | ||||
| *.o | ||||
| *.obj | ||||
|  | ||||
| # Precompiled Headers | ||||
| *.gch | ||||
| *.pch | ||||
|  | ||||
| # Compiled Dynamic libraries | ||||
| *.so | ||||
| *.dylib | ||||
| *.dll | ||||
|  | ||||
| # Fortran module files | ||||
| *.mod | ||||
| *.smod | ||||
|  | ||||
| # Compiled Static libraries | ||||
| *.lai | ||||
| *.la | ||||
| *.a | ||||
| *.lib | ||||
|  | ||||
| # Executables | ||||
| *.exe | ||||
| *.out | ||||
| *.app | ||||
|  | ||||
							
								
								
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,3 @@ | ||||
| [submodule "components/ttn-esp32"] | ||||
| 	path = components/ttn-esp32 | ||||
| [submodule "node/components/ttn-esp32"] | ||||
| 	path = node/components/ttn-esp32 | ||||
| 	url = https://git.mosad.xyz/localhorst/ttn-esp32.git | ||||
|  | ||||
							
								
								
									
										85
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										85
									
								
								README.md
									
									
									
									
									
								
							| @ -30,5 +30,90 @@ TTN LoRa frequency / region | ||||
| 3. Build with ESP-IDF extension in VSCodium | ||||
|  | ||||
|  | ||||
| ## MQTT Endpoint ## | ||||
|  | ||||
| `pip3 install paho-mqtt` | ||||
|  | ||||
| - `mkdir /opt/msv-clubhouse-backend/` | ||||
| - `cd /opt/msv-clubhouse-backend/` | ||||
| - import `msv_clubhouse_backend.py` and `config.py` | ||||
| - Set the constants in `config.py` | ||||
| - `chmod +x /opt/msv-clubhouse-backend/msv_clubhouse_backend.py`  | ||||
| - `chown -R prometheus /opt/msv-clubhouse-backend/` | ||||
| - `nano /etc/systemd/system/msv-clubhouse-backend.service` | ||||
| - `systemctl daemon-reload && systemctl enable --now msv-clubhouse-backend.service` | ||||
|  | ||||
| JS Payload Formatter: | ||||
|  | ||||
| ``` | ||||
| function Decoder(bytes, port) { | ||||
|   var decoded = {}; | ||||
|    | ||||
|   // temperature  | ||||
|   rawTemp = bytes[0] + bytes[1] * 256; | ||||
|   decoded.degreesC = sflt162f(rawTemp) * 100; | ||||
|    | ||||
|   // pressure  | ||||
|   rawPressure = bytes[2] + bytes[3] * 256; | ||||
|   decoded.pressure = sflt162f(rawPressure) * 100; | ||||
|    | ||||
|   // windspeed  | ||||
|   rawWindspeed = bytes[4] + bytes[5] * 256; | ||||
|   decoded.windspeed = sflt162f(rawWindspeed) * 100; | ||||
|    | ||||
|   // winddirection  | ||||
|   rawWinddirection = bytes[6] + bytes[7] * 256; | ||||
|   decoded.winddirection = sflt162f(rawWinddirection) * 100; | ||||
|    | ||||
|   if(bytes[8] === 0){ | ||||
|     decoded.dooropen = false; | ||||
|   }else{ | ||||
|     decoded.dooropen = true; | ||||
|   } | ||||
|    | ||||
|    | ||||
|   return decoded; | ||||
| } | ||||
|  | ||||
| function sflt162f(rawSflt16) | ||||
| 	{ | ||||
| 	// rawSflt16 is the 2-byte number decoded from wherever; | ||||
| 	// it's in range 0..0xFFFF | ||||
| 	// bit 15 is the sign bit | ||||
| 	// bits 14..11 are the exponent | ||||
| 	// bits 10..0 are the the mantissa. Unlike IEEE format,  | ||||
| 	// 	the msb is transmitted; this means that numbers | ||||
| 	//	might not be normalized, but makes coding for | ||||
| 	//	underflow easier. | ||||
| 	// As with IEEE format, negative zero is possible, so | ||||
| 	// we special-case that in hopes that JavaScript will | ||||
| 	// also cooperate. | ||||
| 	// | ||||
| 	// The result is a number in the open interval (-1.0, 1.0); | ||||
| 	//  | ||||
| 	 | ||||
| 	// throw away high bits for repeatability. | ||||
| 	rawSflt16 &= 0xFFFF; | ||||
|  | ||||
| 	// special case minus zero: | ||||
| 	if (rawSflt16 == 0x8000) | ||||
| 		return -0.0; | ||||
|  | ||||
| 	// extract the sign. | ||||
| 	var sSign = ((rawSflt16 & 0x8000) !== 0) ? -1 : 1; | ||||
| 	 | ||||
| 	// extract the exponent | ||||
| 	var exp1 = (rawSflt16 >> 11) & 0xF; | ||||
|  | ||||
| 	// extract the "mantissa" (the fractional part) | ||||
| 	var mant1 = (rawSflt16 & 0x7FF) / 2048.0; | ||||
|  | ||||
| 	// convert back to a floating point number. We hope  | ||||
| 	// that Math.pow(2, k) is handled efficiently by | ||||
| 	// the JS interpreter! If this is time critical code, | ||||
| 	// you can replace by a suitable shift and divide. | ||||
| 	var f_unscaled = sSign * mant1 * Math.pow(2, exp1 - 15); | ||||
|  | ||||
| 	return f_unscaled; | ||||
| 	} | ||||
|     ``` | ||||
							
								
								
									
										12
									
								
								backend/config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								backend/config.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Author:                     Hendrik Schutter, mail@hendrikschutter.com | ||||
| """ | ||||
|  | ||||
| hostName = "127.0.0.1" | ||||
| serverPort = 9101 | ||||
| exporter_prefix = "msv_clubhouse_" | ||||
|  | ||||
| ttn_user = "USER@ttn" | ||||
| ttn_key = "TTN KEY" | ||||
| ttn_region = "EU1"	 | ||||
							
								
								
									
										15
									
								
								backend/msv-clubhouse-backend.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								backend/msv-clubhouse-backend.service
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| [Unit] | ||||
| Description=MSV-Clubhouse-Backend | ||||
| After=syslog.target | ||||
| After=network.target | ||||
|  | ||||
| [Service] | ||||
| RestartSec=2s | ||||
| Type=oneshot | ||||
| User=prometheus | ||||
| Group=prometheus | ||||
| WorkingDirectory=/opt/msv-clubhouse-backend/ | ||||
| ExecStart=/usr/bin/python3 /opt/msv-clubhouse-backend/msv_clubhouse_backend.py | ||||
|  | ||||
| [Install] | ||||
| WantedBy=multi-user.target  | ||||
							
								
								
									
										159
									
								
								backend/msv_clubhouse_backend.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								backend/msv_clubhouse_backend.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,159 @@ | ||||
| #!/usr/bin/env python3 | ||||
| # -*- coding: utf-8 -*- | ||||
| """ Author:                     Hendrik Schutter, mail@hendrikschutter.com | ||||
| """ | ||||
|  | ||||
| from http.server import BaseHTTPRequestHandler, HTTPServer | ||||
| import paho.mqtt.client as mqtt | ||||
| from datetime import datetime | ||||
| import threading | ||||
| import time | ||||
| import json | ||||
| import config | ||||
|  | ||||
| scrape_healthy = True | ||||
| startTime = datetime.now() | ||||
| node_metrics = list() | ||||
| mutex = threading.Lock() | ||||
| request_count = 0 | ||||
|  | ||||
| class RequestHandler(BaseHTTPRequestHandler): | ||||
|  | ||||
|     def get_metrics(self): | ||||
|         global request_count | ||||
|         global node_metrics | ||||
|         global mutex | ||||
|         mutex.acquire() | ||||
|         self.send_response(200) | ||||
|         self.send_header("Content-type", "text/html") | ||||
|         self.end_headers() | ||||
|         self.wfile.write(bytes(config.exporter_prefix + "expoter_duration_seconds_sum " + str(int((datetime.now() - startTime).total_seconds())) + "\n", "utf-8")) | ||||
|         self.wfile.write(bytes(config.exporter_prefix + "exporter_request_count " + str(request_count) + "\n", "utf-8")) | ||||
|         self.wfile.write(bytes(config.exporter_prefix + "exporter_scrape_healthy " + str(int(scrape_healthy)) + "\n", "utf-8")) | ||||
|          | ||||
|         for metric in node_metrics: | ||||
|             #print(metric) | ||||
|             self.wfile.write(bytes(config.exporter_prefix + metric + "\n", "utf-8")) | ||||
|  | ||||
|         mutex.release() | ||||
|          | ||||
|     def do_GET(self): | ||||
|         global request_count | ||||
|         request_count = request_count + 1 | ||||
|         print("Request: " + self.path) | ||||
|         if (self.path.startswith("/metrics")):  | ||||
|             self.get_metrics() | ||||
|         else: | ||||
|             self.send_response(200) | ||||
|             self.send_header("Content-type", "text/html") | ||||
|             self.end_headers() | ||||
|             self.wfile.write(bytes("<html>", "utf-8")) | ||||
|             self.wfile.write(bytes("<head><title>MSV Clubhouse exporter</title></head>", "utf-8")) | ||||
|             self.wfile.write(bytes("<body>", "utf-8")) | ||||
|             self.wfile.write(bytes('<h1>msv-clubhouse exporter based on data from LoRaWAN TTN node.</h1>', "utf-8")) | ||||
|             self.wfile.write(bytes('<p><a href="/metrics">Metrics</a></p>', "utf-8")) | ||||
|             self.wfile.write(bytes("</body>", "utf-8")) | ||||
|             self.wfile.write(bytes("</html>", "utf-8")) | ||||
|  | ||||
| def update_metrics(payload, metadata): | ||||
|     #print("Payload: "+ str(payload)) | ||||
|     #print("Metadata: "+ str(metadata)) | ||||
|  | ||||
|     global node_metrics | ||||
|     global mutex | ||||
|     global scrape_healthy | ||||
|     mutex.acquire() | ||||
|     scrape_healthy = True | ||||
|     node_metrics.clear() | ||||
|  | ||||
|     if "degreesC" in payload: | ||||
|         print("set degree: " + str(float(payload["degreesC"]))) | ||||
|         node_metrics.append("temperature " + str(float(payload["degreesC"]))) | ||||
|  | ||||
|     if "pressure" in payload: | ||||
|         print("set pressure: " + str(float(payload["pressure"]))) | ||||
|         node_metrics.append("pressure " + str(float(payload["pressure"]))) | ||||
|  | ||||
|     if "winddirection" in payload: | ||||
|         print("set winddirection: " + str(float(payload["winddirection"]))) | ||||
|         node_metrics.append("winddirection " + str(float(payload["winddirection"]))) | ||||
|  | ||||
|     if "windspeed" in payload: | ||||
|         print("set windspeed: " + str(float(payload["windspeed"]))) | ||||
|         node_metrics.append("windspeed " + str(float(payload["windspeed"]))) | ||||
|  | ||||
|     if "dooropen" in payload: | ||||
|         print("set dooropen: " + str(bool(payload["dooropen"]))) | ||||
|         node_metrics.append("dooropen " + str(int(payload["dooropen"]))) | ||||
|  | ||||
|    # if "gateway_id" in metadata[0]["gateway_ids"]: | ||||
|    #     print("set gateway_id: " + str(metadata[0]["gateway_ids"]["gateway_id"])) | ||||
|    #     node_metrics.append("gateway_id " + str(metadata[0]["gateway_ids"]["gateway_id"])) | ||||
|  | ||||
|     if "rssi" in metadata[0]: | ||||
|         print("set rssi: " + str(int(metadata[0]["rssi"]))) | ||||
|         node_metrics.append("rssi " + str(int(metadata[0]["rssi"]))) | ||||
|  | ||||
|     if "channel_rssi" in metadata[0]: | ||||
|         print("set channel_rssi: " + str(int(metadata[0]["channel_rssi"]))) | ||||
|         node_metrics.append("channel_rssi " + str(int(metadata[0]["channel_rssi"]))) | ||||
|  | ||||
|     if "snr" in metadata[0]: | ||||
|         print("set snr: " + str(float(metadata[0]["snr"]))) | ||||
|         node_metrics.append("snr " + str(float(metadata[0]["snr"]))) | ||||
|  | ||||
|      | ||||
|     #scrape_healthy = False | ||||
|  | ||||
|     mutex.release() | ||||
|  | ||||
| def on_connect(mqttc, obj, flags, rc): | ||||
|     print("\nConnected to MQTT: rc = " + str(rc)) | ||||
|  | ||||
| def on_message(mqttc, obj, msg): | ||||
|     #print("\nMessage: " + msg.topic + " " + str(msg.qos)) | ||||
|     parsedJSON = json.loads(msg.payload) | ||||
|     #print(json.dumps(parsedJSON, indent=4)) | ||||
|  | ||||
|     try:  | ||||
|         uplink_message = parsedJSON["uplink_message"]; | ||||
|         update_metrics(uplink_message["decoded_payload"], uplink_message["rx_metadata"]) | ||||
|     except: | ||||
|         print("Unable to parse uplink") | ||||
|  | ||||
| def on_subscribe(mqttc, obj, mid, granted_qos): | ||||
|     print("\nSubscribed to MQTT: " + str(mid) + " " + str(granted_qos)) | ||||
|  | ||||
| def poll_mqtt(mqttc): | ||||
| 	while True: | ||||
| 			mqttc.loop(10) 	# seconds timeout | ||||
|  | ||||
| def main(): | ||||
| 	print("starting ...")	 | ||||
|  | ||||
| 	mqttc = mqtt.Client() | ||||
| 	mqttc.on_connect = on_connect | ||||
| 	mqttc.on_subscribe = on_subscribe | ||||
| 	mqttc.on_message = on_message | ||||
| 	mqttc.username_pw_set(config.ttn_user, config.ttn_key) | ||||
| 	mqttc.tls_set()	 | ||||
| 	mqttc.connect(config.ttn_region.lower() + ".cloud.thethings.network", 8883, 60) | ||||
| 	mqttc.subscribe("#", 0)	# all device uplinks | ||||
|  | ||||
|     # run mqtt in thread forever | ||||
| 	poll_mqtt_thread = threading.Thread(target=poll_mqtt, args=((mqttc,))) | ||||
| 	poll_mqtt_thread.start() | ||||
|  | ||||
| 	webServer = HTTPServer((config.hostName, config.serverPort), RequestHandler) | ||||
| 	print("Server started http://%s:%s" % (config.hostName, config.serverPort)) | ||||
| 	try: | ||||
| 		webServer.serve_forever() | ||||
| 	except KeyboardInterrupt: | ||||
| 		pass | ||||
|  | ||||
| 	webServer.server_close() | ||||
| 	print("Server stopped.") | ||||
| 	poll_mqtt_thread.join() | ||||
|  | ||||
| if __name__ == "__main__": | ||||
| 	main() | ||||
 Submodule components/ttn-esp32 deleted from 877784640d
									
								
							
							
								
								
									
										766
									
								
								frontend/grafana_dashboard.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										766
									
								
								frontend/grafana_dashboard.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,766 @@ | ||||
| { | ||||
|   "annotations": { | ||||
|     "list": [ | ||||
|       { | ||||
|         "builtIn": 1, | ||||
|         "datasource": { | ||||
|           "type": "grafana", | ||||
|           "uid": "-- Grafana --" | ||||
|         }, | ||||
|         "enable": true, | ||||
|         "hide": true, | ||||
|         "iconColor": "rgba(0, 211, 255, 1)", | ||||
|         "name": "Annotations & Alerts", | ||||
|         "target": { | ||||
|           "limit": 100, | ||||
|           "matchAny": false, | ||||
|           "tags": [], | ||||
|           "type": "dashboard" | ||||
|         }, | ||||
|         "type": "dashboard" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   "editable": true, | ||||
|   "fiscalYearStartMonth": 0, | ||||
|   "graphTooltip": 0, | ||||
|   "id": 16, | ||||
|   "links": [], | ||||
|   "liveNow": false, | ||||
|   "panels": [ | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "description": "Wenn die Türe offen, dann ist wohl jemand am Platz.", | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "thresholds" | ||||
|           }, | ||||
|           "mappings": [ | ||||
|             { | ||||
|               "options": { | ||||
|                 "0": { | ||||
|                   "color": "red", | ||||
|                   "index": 1, | ||||
|                   "text": "Türe geschlossen" | ||||
|                 }, | ||||
|                 "1": { | ||||
|                   "color": "green", | ||||
|                   "index": 0, | ||||
|                   "text": "Türe offen" | ||||
|                 } | ||||
|               }, | ||||
|               "type": "value" | ||||
|             } | ||||
|           ], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 6, | ||||
|         "w": 5, | ||||
|         "x": 0, | ||||
|         "y": 0 | ||||
|       }, | ||||
|       "id": 2, | ||||
|       "options": { | ||||
|         "colorMode": "value", | ||||
|         "graphMode": "area", | ||||
|         "justifyMode": "auto", | ||||
|         "orientation": "auto", | ||||
|         "reduceOptions": { | ||||
|           "calcs": [ | ||||
|             "lastNotNull" | ||||
|           ], | ||||
|           "fields": "", | ||||
|           "values": false | ||||
|         }, | ||||
|         "textMode": "auto" | ||||
|       }, | ||||
|       "pluginVersion": "9.3.6", | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_dooropen", | ||||
|           "legendFormat": "__auto", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Türe zur Vereinshütte", | ||||
|       "type": "stat" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "thresholds" | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "pressurehpa" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 6, | ||||
|         "w": 5, | ||||
|         "x": 5, | ||||
|         "y": 0 | ||||
|       }, | ||||
|       "id": 5, | ||||
|       "options": { | ||||
|         "orientation": "auto", | ||||
|         "reduceOptions": { | ||||
|           "calcs": [ | ||||
|             "lastNotNull" | ||||
|           ], | ||||
|           "fields": "", | ||||
|           "values": false | ||||
|         }, | ||||
|         "showThresholdLabels": false, | ||||
|         "showThresholdMarkers": true | ||||
|       }, | ||||
|       "pluginVersion": "9.3.6", | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_pressure", | ||||
|           "legendFormat": "Luftdruck Außen", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Aktueller Luftdruck Außen ", | ||||
|       "type": "gauge" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "thresholds" | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "celsius" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 6, | ||||
|         "w": 5, | ||||
|         "x": 10, | ||||
|         "y": 0 | ||||
|       }, | ||||
|       "id": 6, | ||||
|       "options": { | ||||
|         "orientation": "auto", | ||||
|         "reduceOptions": { | ||||
|           "calcs": [ | ||||
|             "lastNotNull" | ||||
|           ], | ||||
|           "fields": "", | ||||
|           "values": false | ||||
|         }, | ||||
|         "showThresholdLabels": false, | ||||
|         "showThresholdMarkers": true | ||||
|       }, | ||||
|       "pluginVersion": "9.3.6", | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_temperature", | ||||
|           "legendFormat": "Temperatur Außen", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Aktuelle Temperatur Außen ", | ||||
|       "type": "gauge" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "thresholds" | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "degree" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 6, | ||||
|         "w": 4, | ||||
|         "x": 15, | ||||
|         "y": 0 | ||||
|       }, | ||||
|       "id": 8, | ||||
|       "options": { | ||||
|         "orientation": "auto", | ||||
|         "reduceOptions": { | ||||
|           "calcs": [ | ||||
|             "lastNotNull" | ||||
|           ], | ||||
|           "fields": "", | ||||
|           "values": false | ||||
|         }, | ||||
|         "showThresholdLabels": false, | ||||
|         "showThresholdMarkers": true | ||||
|       }, | ||||
|       "pluginVersion": "9.3.6", | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_winddirection", | ||||
|           "legendFormat": "Windrichtung", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Aktuelle Windrichtung", | ||||
|       "type": "gauge" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "thresholds" | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "velocityms" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 6, | ||||
|         "w": 4, | ||||
|         "x": 19, | ||||
|         "y": 0 | ||||
|       }, | ||||
|       "id": 9, | ||||
|       "options": { | ||||
|         "orientation": "auto", | ||||
|         "reduceOptions": { | ||||
|           "calcs": [ | ||||
|             "lastNotNull" | ||||
|           ], | ||||
|           "fields": "", | ||||
|           "values": false | ||||
|         }, | ||||
|         "showThresholdLabels": false, | ||||
|         "showThresholdMarkers": true | ||||
|       }, | ||||
|       "pluginVersion": "9.3.6", | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_winddirection", | ||||
|           "legendFormat": "Windstärke", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Aktuelle Windstärke", | ||||
|       "type": "gauge" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "palette-classic" | ||||
|           }, | ||||
|           "custom": { | ||||
|             "axisCenteredZero": false, | ||||
|             "axisColorMode": "text", | ||||
|             "axisLabel": "", | ||||
|             "axisPlacement": "auto", | ||||
|             "barAlignment": 0, | ||||
|             "drawStyle": "line", | ||||
|             "fillOpacity": 0, | ||||
|             "gradientMode": "none", | ||||
|             "hideFrom": { | ||||
|               "legend": false, | ||||
|               "tooltip": false, | ||||
|               "viz": false | ||||
|             }, | ||||
|             "lineInterpolation": "linear", | ||||
|             "lineWidth": 1, | ||||
|             "pointSize": 5, | ||||
|             "scaleDistribution": { | ||||
|               "type": "linear" | ||||
|             }, | ||||
|             "showPoints": "auto", | ||||
|             "spanNulls": false, | ||||
|             "stacking": { | ||||
|               "group": "A", | ||||
|               "mode": "none" | ||||
|             }, | ||||
|             "thresholdsStyle": { | ||||
|               "mode": "off" | ||||
|             } | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "pressurehpa" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 9, | ||||
|         "w": 12, | ||||
|         "x": 0, | ||||
|         "y": 6 | ||||
|       }, | ||||
|       "id": 4, | ||||
|       "options": { | ||||
|         "legend": { | ||||
|           "calcs": [], | ||||
|           "displayMode": "list", | ||||
|           "placement": "bottom", | ||||
|           "showLegend": true | ||||
|         }, | ||||
|         "tooltip": { | ||||
|           "mode": "single", | ||||
|           "sort": "none" | ||||
|         } | ||||
|       }, | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_pressure", | ||||
|           "legendFormat": "Luftdruck Außen", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Luftdruck Außen", | ||||
|       "type": "timeseries" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "palette-classic" | ||||
|           }, | ||||
|           "custom": { | ||||
|             "axisCenteredZero": false, | ||||
|             "axisColorMode": "text", | ||||
|             "axisLabel": "", | ||||
|             "axisPlacement": "auto", | ||||
|             "barAlignment": 0, | ||||
|             "drawStyle": "line", | ||||
|             "fillOpacity": 0, | ||||
|             "gradientMode": "none", | ||||
|             "hideFrom": { | ||||
|               "legend": false, | ||||
|               "tooltip": false, | ||||
|               "viz": false | ||||
|             }, | ||||
|             "lineInterpolation": "linear", | ||||
|             "lineWidth": 1, | ||||
|             "pointSize": 5, | ||||
|             "scaleDistribution": { | ||||
|               "type": "linear" | ||||
|             }, | ||||
|             "showPoints": "auto", | ||||
|             "spanNulls": false, | ||||
|             "stacking": { | ||||
|               "group": "A", | ||||
|               "mode": "none" | ||||
|             }, | ||||
|             "thresholdsStyle": { | ||||
|               "mode": "off" | ||||
|             } | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "celsius" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 9, | ||||
|         "w": 12, | ||||
|         "x": 12, | ||||
|         "y": 6 | ||||
|       }, | ||||
|       "id": 7, | ||||
|       "options": { | ||||
|         "legend": { | ||||
|           "calcs": [], | ||||
|           "displayMode": "list", | ||||
|           "placement": "bottom", | ||||
|           "showLegend": true | ||||
|         }, | ||||
|         "tooltip": { | ||||
|           "mode": "single", | ||||
|           "sort": "none" | ||||
|         } | ||||
|       }, | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_temperature", | ||||
|           "legendFormat": "Luftdruck Außen", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "Tempertur Außen", | ||||
|       "type": "timeseries" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "palette-classic" | ||||
|           }, | ||||
|           "custom": { | ||||
|             "axisCenteredZero": false, | ||||
|             "axisColorMode": "text", | ||||
|             "axisLabel": "", | ||||
|             "axisPlacement": "auto", | ||||
|             "barAlignment": 0, | ||||
|             "drawStyle": "line", | ||||
|             "fillOpacity": 0, | ||||
|             "gradientMode": "none", | ||||
|             "hideFrom": { | ||||
|               "legend": false, | ||||
|               "tooltip": false, | ||||
|               "viz": false | ||||
|             }, | ||||
|             "lineInterpolation": "linear", | ||||
|             "lineWidth": 1, | ||||
|             "pointSize": 5, | ||||
|             "scaleDistribution": { | ||||
|               "type": "linear" | ||||
|             }, | ||||
|             "showPoints": "auto", | ||||
|             "spanNulls": false, | ||||
|             "stacking": { | ||||
|               "group": "A", | ||||
|               "mode": "none" | ||||
|             }, | ||||
|             "thresholdsStyle": { | ||||
|               "mode": "off" | ||||
|             } | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "dB" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 9, | ||||
|         "w": 12, | ||||
|         "x": 0, | ||||
|         "y": 15 | ||||
|       }, | ||||
|       "id": 10, | ||||
|       "options": { | ||||
|         "legend": { | ||||
|           "calcs": [], | ||||
|           "displayMode": "list", | ||||
|           "placement": "bottom", | ||||
|           "showLegend": true | ||||
|         }, | ||||
|         "tooltip": { | ||||
|           "mode": "single", | ||||
|           "sort": "none" | ||||
|         } | ||||
|       }, | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_rssi", | ||||
|           "legendFormat": "RSSI", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "RSSI", | ||||
|       "type": "timeseries" | ||||
|     }, | ||||
|     { | ||||
|       "datasource": { | ||||
|         "type": "prometheus", | ||||
|         "uid": "x08D2Hlnz" | ||||
|       }, | ||||
|       "fieldConfig": { | ||||
|         "defaults": { | ||||
|           "color": { | ||||
|             "mode": "palette-classic" | ||||
|           }, | ||||
|           "custom": { | ||||
|             "axisCenteredZero": false, | ||||
|             "axisColorMode": "text", | ||||
|             "axisLabel": "", | ||||
|             "axisPlacement": "auto", | ||||
|             "barAlignment": 0, | ||||
|             "drawStyle": "line", | ||||
|             "fillOpacity": 0, | ||||
|             "gradientMode": "none", | ||||
|             "hideFrom": { | ||||
|               "legend": false, | ||||
|               "tooltip": false, | ||||
|               "viz": false | ||||
|             }, | ||||
|             "lineInterpolation": "linear", | ||||
|             "lineWidth": 1, | ||||
|             "pointSize": 5, | ||||
|             "scaleDistribution": { | ||||
|               "type": "linear" | ||||
|             }, | ||||
|             "showPoints": "auto", | ||||
|             "spanNulls": false, | ||||
|             "stacking": { | ||||
|               "group": "A", | ||||
|               "mode": "none" | ||||
|             }, | ||||
|             "thresholdsStyle": { | ||||
|               "mode": "off" | ||||
|             } | ||||
|           }, | ||||
|           "decimals": 2, | ||||
|           "mappings": [], | ||||
|           "thresholds": { | ||||
|             "mode": "absolute", | ||||
|             "steps": [ | ||||
|               { | ||||
|                 "color": "green", | ||||
|                 "value": null | ||||
|               }, | ||||
|               { | ||||
|                 "color": "red", | ||||
|                 "value": 80 | ||||
|               } | ||||
|             ] | ||||
|           }, | ||||
|           "unit": "dB" | ||||
|         }, | ||||
|         "overrides": [] | ||||
|       }, | ||||
|       "gridPos": { | ||||
|         "h": 9, | ||||
|         "w": 12, | ||||
|         "x": 12, | ||||
|         "y": 15 | ||||
|       }, | ||||
|       "id": 12, | ||||
|       "options": { | ||||
|         "legend": { | ||||
|           "calcs": [], | ||||
|           "displayMode": "list", | ||||
|           "placement": "bottom", | ||||
|           "showLegend": true | ||||
|         }, | ||||
|         "tooltip": { | ||||
|           "mode": "single", | ||||
|           "sort": "none" | ||||
|         } | ||||
|       }, | ||||
|       "targets": [ | ||||
|         { | ||||
|           "datasource": { | ||||
|             "type": "prometheus", | ||||
|             "uid": "x08D2Hlnz" | ||||
|           }, | ||||
|           "editorMode": "builder", | ||||
|           "expr": "msv_clubhouse_snr", | ||||
|           "legendFormat": "SNR", | ||||
|           "range": true, | ||||
|           "refId": "A" | ||||
|         } | ||||
|       ], | ||||
|       "title": "SNR", | ||||
|       "type": "timeseries" | ||||
|     } | ||||
|   ], | ||||
|   "schemaVersion": 37, | ||||
|   "style": "dark", | ||||
|   "tags": [], | ||||
|   "templating": { | ||||
|     "list": [] | ||||
|   }, | ||||
|   "time": { | ||||
|     "from": "now-6h", | ||||
|     "to": "now" | ||||
|   }, | ||||
|   "timepicker": {}, | ||||
|   "timezone": "", | ||||
|   "title": "MSV Moos Modellflugplatz", | ||||
|   "uid": "nuH5csxVz", | ||||
|   "version": 6, | ||||
|   "weekStart": "" | ||||
| } | ||||
							
								
								
									
										0
									
								
								node/components/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								node/components/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										22
									
								
								node/main/i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								node/main/i2c.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
|  | ||||
|  | ||||
| #include "i2c.h" | ||||
|  | ||||
| #include "esp_log.h" | ||||
|  | ||||
|  | ||||
| void i2c_init() | ||||
| { | ||||
| 	i2c_config_t i2c_config; | ||||
|  | ||||
| 		i2c_config.mode = I2C_MODE_MASTER; | ||||
| 		i2c_config.sda_io_num = I2C_SDA_PIN; | ||||
| 		i2c_config.scl_io_num = I2C_SCL_PIN; | ||||
| 		i2c_config.sda_pullup_en = GPIO_PULLUP_ENABLE; | ||||
| 		i2c_config.scl_pullup_en = GPIO_PULLUP_ENABLE; | ||||
| 		i2c_config.master.clk_speed = I2C_MASTER_FREQ_HZ; | ||||
|  | ||||
|  | ||||
| 	ESP_ERROR_CHECK(i2c_param_config(I2C_NUM, &i2c_config)); | ||||
| 	ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0)); | ||||
| } | ||||
							
								
								
									
										24
									
								
								node/main/i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								node/main/i2c.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #ifndef _I2C_H_ | ||||
| #define _I2C_H_ | ||||
|  | ||||
| #define I2C_SDA_PIN GPIO_NUM_4 | ||||
| #define I2C_SCL_PIN GPIO_NUM_15 | ||||
|  | ||||
| #define I2C_NUM I2C_NUM_0 | ||||
| //#define I2C_NUM I2C_NUM | ||||
|  | ||||
| #define I2C_MASTER_FREQ_HZ 400000U /*!< I2C clock of SSD1306 can run at 400 kHz max. */ | ||||
|  | ||||
|  | ||||
| class I2C_Driver | ||||
| { | ||||
|  | ||||
|  | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
| void i2c_init(); | ||||
|  | ||||
|  | ||||
| #endif /* _I2C_H_ */ | ||||
							
								
								
									
										174
									
								
								node/main/oled/font8x8_basic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								node/main/oled/font8x8_basic.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | ||||
| /* | ||||
|  * font8x8_basic.h | ||||
|  * | ||||
|  *  Created on: 2017/05/03 | ||||
|  *      Author: yanbe | ||||
|  */ | ||||
|  | ||||
| #ifndef MAIN_FONT8X8_BASIC_H_ | ||||
| #define MAIN_FONT8X8_BASIC_H_ | ||||
|  | ||||
| #include "freertos/FreeRTOS.h" | ||||
|  | ||||
| /* | ||||
|    Constant: font8x8_basic_tr | ||||
|    Contains an 90 digree transposed 8x8 font map for unicode points  | ||||
|    U+0000 - U+007F (basic latin) | ||||
|     | ||||
|    To make it easy to use with SSD1306's GDDRAM mapping and API, | ||||
|    this constant is an 90 degree transposed. | ||||
|    The original version written by Marcel Sondaar is availble at: | ||||
|    https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h  | ||||
|    Conversion is done via following procedure: | ||||
|     | ||||
| 	for (int code = 0; code < 128; code++) { | ||||
| 		uint8_t trans[8]; | ||||
| 		for (int w = 0; w < 8; w++) { | ||||
| 			trans[w] = 0x00; | ||||
| 			for (int b = 0; b < 8; b++) { | ||||
| 				trans[w] |= ((font8x8_basic[code][b] & (1 << w)) >> w) << b; | ||||
| 			} | ||||
| 		} | ||||
| 	 | ||||
| 		for (int w = 0; w < 8; w++) { | ||||
| 			if (w == 0) { printf("    { "); } | ||||
| 			printf("0x%.2X", trans[w]); | ||||
| 			if (w < 7) { printf(", "); } | ||||
| 			if (w == 7) { printf(" },   // U+00%.2X (%c)\n", code, code); } | ||||
| 		} | ||||
| 	} | ||||
| */ | ||||
|  | ||||
| uint8_t font8x8_basic_tr[128][8] = { | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0000 (nul) | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0001 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0002 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0003 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0004 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0005 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0006 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0007 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0008 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0009 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000A | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000B | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000C | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000D | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000E | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+000F | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0010 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0011 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0012 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0013 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0014 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0015 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0016 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0017 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0018 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0019 | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001A | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001B | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001C | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001D | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001E | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+001F | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0020 (space) | ||||
|     { 0x00, 0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00 },   // U+0021 (!) | ||||
|     { 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00 },   // U+0022 (") | ||||
|     { 0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00 },   // U+0023 (#) | ||||
|     { 0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00 },   // U+0024 ($) | ||||
|     { 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00 },   // U+0025 (%) | ||||
|     { 0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00 },   // U+0026 (&) | ||||
|     { 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 },   // U+0027 (') | ||||
|     { 0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00 },   // U+0028 (() | ||||
|     { 0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00 },   // U+0029 ()) | ||||
|     { 0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08 },   // U+002A (*) | ||||
|     { 0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00 },   // U+002B (+) | ||||
|     { 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00 },   // U+002C (,) | ||||
|     { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 },   // U+002D (-) | ||||
|     { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 },   // U+002E (.) | ||||
|     { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 },   // U+002F (/) | ||||
|     { 0x3E, 0x7F, 0x71, 0x59, 0x4D, 0x7F, 0x3E, 0x00 },   // U+0030 (0) | ||||
|     { 0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00 },   // U+0031 (1) | ||||
|     { 0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00 },   // U+0032 (2) | ||||
|     { 0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 },   // U+0033 (3) | ||||
|     { 0x18, 0x1C, 0x16, 0x53, 0x7F, 0x7F, 0x50, 0x00 },   // U+0034 (4) | ||||
|     { 0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00 },   // U+0035 (5) | ||||
|     { 0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00 },   // U+0036 (6) | ||||
|     { 0x03, 0x03, 0x71, 0x79, 0x0F, 0x07, 0x00, 0x00 },   // U+0037 (7) | ||||
|     { 0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 },   // U+0038 (8) | ||||
|     { 0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00 },   // U+0039 (9) | ||||
|     { 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 },   // U+003A (:) | ||||
|     { 0x00, 0x80, 0xE6, 0x66, 0x00, 0x00, 0x00, 0x00 },   // U+003B (;) | ||||
|     { 0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00 },   // U+003C (<) | ||||
|     { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00 },   // U+003D (=) | ||||
|     { 0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00 },   // U+003E (>) | ||||
|     { 0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00 },   // U+003F (?) | ||||
|     { 0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00 },   // U+0040 (@) | ||||
|     { 0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00 },   // U+0041 (A) | ||||
|     { 0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00 },   // U+0042 (B) | ||||
|     { 0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00 },   // U+0043 (C) | ||||
|     { 0x41, 0x7F, 0x7F, 0x41, 0x63, 0x3E, 0x1C, 0x00 },   // U+0044 (D) | ||||
|     { 0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00 },   // U+0045 (E) | ||||
|     { 0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00 },   // U+0046 (F) | ||||
|     { 0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00 },   // U+0047 (G) | ||||
|     { 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00 },   // U+0048 (H) | ||||
|     { 0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00 },   // U+0049 (I) | ||||
|     { 0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00 },   // U+004A (J) | ||||
|     { 0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00 },   // U+004B (K) | ||||
|     { 0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00 },   // U+004C (L) | ||||
|     { 0x7F, 0x7F, 0x0E, 0x1C, 0x0E, 0x7F, 0x7F, 0x00 },   // U+004D (M) | ||||
|     { 0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00 },   // U+004E (N) | ||||
|     { 0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00 },   // U+004F (O) | ||||
|     { 0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00 },   // U+0050 (P) | ||||
|     { 0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00 },   // U+0051 (Q) | ||||
|     { 0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00 },   // U+0052 (R) | ||||
|     { 0x26, 0x6F, 0x4D, 0x59, 0x73, 0x32, 0x00, 0x00 },   // U+0053 (S) | ||||
|     { 0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00 },   // U+0054 (T) | ||||
|     { 0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00 },   // U+0055 (U) | ||||
|     { 0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00 },   // U+0056 (V) | ||||
|     { 0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00 },   // U+0057 (W) | ||||
|     { 0x43, 0x67, 0x3C, 0x18, 0x3C, 0x67, 0x43, 0x00 },   // U+0058 (X) | ||||
|     { 0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00 },   // U+0059 (Y) | ||||
|     { 0x47, 0x63, 0x71, 0x59, 0x4D, 0x67, 0x73, 0x00 },   // U+005A (Z) | ||||
|     { 0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00 },   // U+005B ([) | ||||
|     { 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00 },   // U+005C (\) | ||||
|     { 0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00 },   // U+005D (]) | ||||
|     { 0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00 },   // U+005E (^) | ||||
|     { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 },   // U+005F (_) | ||||
|     { 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00 },   // U+0060 (`) | ||||
|     { 0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00 },   // U+0061 (a) | ||||
|     { 0x41, 0x7F, 0x3F, 0x48, 0x48, 0x78, 0x30, 0x00 },   // U+0062 (b) | ||||
|     { 0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00 },   // U+0063 (c) | ||||
|     { 0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00 },   // U+0064 (d) | ||||
|     { 0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00 },   // U+0065 (e) | ||||
|     { 0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00 },   // U+0066 (f) | ||||
|     { 0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00 },   // U+0067 (g) | ||||
|     { 0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00 },   // U+0068 (h) | ||||
|     { 0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00 },   // U+0069 (i) | ||||
|     { 0x60, 0xE0, 0x80, 0x80, 0xFD, 0x7D, 0x00, 0x00 },   // U+006A (j) | ||||
|     { 0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00 },   // U+006B (k) | ||||
|     { 0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00 },   // U+006C (l) | ||||
|     { 0x7C, 0x7C, 0x18, 0x38, 0x1C, 0x7C, 0x78, 0x00 },   // U+006D (m) | ||||
|     { 0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00 },   // U+006E (n) | ||||
|     { 0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00 },   // U+006F (o) | ||||
|     { 0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00 },   // U+0070 (p) | ||||
|     { 0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00 },   // U+0071 (q) | ||||
|     { 0x44, 0x7C, 0x78, 0x4C, 0x04, 0x1C, 0x18, 0x00 },   // U+0072 (r) | ||||
|     { 0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00 },   // U+0073 (s) | ||||
|     { 0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00 },   // U+0074 (t) | ||||
|     { 0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00 },   // U+0075 (u) | ||||
|     { 0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00 },   // U+0076 (v) | ||||
|     { 0x3C, 0x7C, 0x70, 0x38, 0x70, 0x7C, 0x3C, 0x00 },   // U+0077 (w) | ||||
|     { 0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00 },   // U+0078 (x) | ||||
|     { 0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00 },   // U+0079 (y) | ||||
|     { 0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00 },   // U+007A (z) | ||||
|     { 0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00 },   // U+007B ({) | ||||
|     { 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00 },   // U+007C (|) | ||||
|     { 0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00 },   // U+007D (}) | ||||
|     { 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00 },   // U+007E (~) | ||||
|     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }    // U+007F | ||||
| }; | ||||
|  | ||||
| #endif /* MAIN_FONT8X8_BASIC_H_ */ | ||||
|  | ||||
							
								
								
									
										180
									
								
								node/main/oled/ssd1366.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								node/main/oled/ssd1366.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,180 @@ | ||||
|  | ||||
| #include "ssd1366.h" | ||||
| #include "font8x8_basic.h" | ||||
| #include <string.h> | ||||
| #include "driver/gpio.h" | ||||
|  | ||||
|  | ||||
| #define SSD1366_RST_PIN GPIO_NUM_16 | ||||
| #define SSD1366_VEXT_PIN GPIO_NUM_21 | ||||
|  | ||||
| #define I2C_NUM I2C_NUM_0 | ||||
|  | ||||
| static const char *tag = "oled"; | ||||
|  | ||||
| void ssd1306_init() | ||||
| { | ||||
| 	esp_err_t espRc; | ||||
| 	gpio_set_direction(SSD1366_RST_PIN, GPIO_MODE_OUTPUT); | ||||
| 	gpio_set_direction(SSD1366_VEXT_PIN, GPIO_MODE_OUTPUT); | ||||
| 	gpio_set_level(SSD1366_VEXT_PIN, 0); //enable power to oled | ||||
| 	gpio_set_level(SSD1366_RST_PIN, 0);  | ||||
| 	vTaskDelay(50 / portTICK_PERIOD_MS); | ||||
| 	gpio_set_level(SSD1366_RST_PIN, 1);  | ||||
|  | ||||
| 	i2c_cmd_handle_t cmd = i2c_cmd_link_create(); | ||||
|  | ||||
| 	i2c_master_start(cmd); | ||||
| 	i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); | ||||
|  | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_OFF, true);				// AE | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_MUX_RATIO, true);			// A8 | ||||
| 	i2c_master_write_byte(cmd, 0x3F, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_OFFSET, true);		// D3 | ||||
| 	i2c_master_write_byte(cmd, 0x00, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_START_LINE, true);	// 40 | ||||
|  | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // reverse left-right mapping | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // reverse up-bottom mapping | ||||
|  | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_DISPLAY_CLK_DIV, true);		// D5 | ||||
| 	i2c_master_write_byte(cmd, 0x80, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_COM_PIN_MAP, true);			// DA | ||||
| 	i2c_master_write_byte(cmd, 0x12, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true);			// 81 | ||||
| 	i2c_master_write_byte(cmd, 0xFF, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_RAM, true);				// A4 | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_VCOMH_DESELCT, true);		// DB | ||||
| 	i2c_master_write_byte(cmd, 0x40, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_MEMORY_ADDR_MODE, true);	// 20 | ||||
| 	//i2c_master_write_byte(cmd, OLED_CMD_SET_HORI_ADDR_MODE, true);	// 00 | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_PAGE_ADDR_MODE, true);		// 02 | ||||
| 	// Set Lower Column Start Address for Page Addressing Mode | ||||
| 	i2c_master_write_byte(cmd, 0x00, true); | ||||
| 	// Set Higher Column Start Address for Page Addressing Mode | ||||
| 	i2c_master_write_byte(cmd, 0x10, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true);			// 8D | ||||
| 	i2c_master_write_byte(cmd, 0x14, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_DEACTIVE_SCROLL, true);			// 2E | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_NORMAL, true);			// A6 | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true); | ||||
|  | ||||
| 	i2c_master_stop(cmd); | ||||
|  | ||||
| 	espRc = i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); | ||||
| 	if (espRc == ESP_OK) | ||||
| 	{ | ||||
| 		ESP_LOGI(tag, "OLED configured successfully"); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc); | ||||
| 	} | ||||
| 	i2c_cmd_link_delete(cmd); | ||||
| } | ||||
|  | ||||
| void i2c_contrast( int contrast) { | ||||
| 	i2c_cmd_handle_t cmd; | ||||
| 	int _contrast = contrast; | ||||
| 	if (contrast < 0x0) _contrast = 0; | ||||
| 	if (contrast > 0xFF) _contrast = 0xFF; | ||||
|  | ||||
| 	cmd = i2c_cmd_link_create(); | ||||
| 	i2c_master_start(cmd); | ||||
| 	i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); | ||||
| 	i2c_master_write_byte(cmd, OLED_CMD_SET_CONTRAST, true);			// 81 | ||||
| 	i2c_master_write_byte(cmd, _contrast, true); | ||||
| 	i2c_master_stop(cmd); | ||||
| 	i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); | ||||
| 	i2c_cmd_link_delete(cmd); | ||||
| } | ||||
|  | ||||
| void ssd1306_display_clear(void) { | ||||
|   i2c_cmd_handle_t cmd; | ||||
|   uint8_t zero[128] = {0}; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     cmd = i2c_cmd_link_create(); | ||||
|     i2c_master_start(cmd); | ||||
|       i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
|       i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_SINGLE, true); | ||||
|       i2c_master_write_byte(cmd, 0xB0 | i, true); // Set GDDRAM page start address | ||||
|         i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); | ||||
|         i2c_master_write(cmd, zero, 128, true); | ||||
|     i2c_master_stop(cmd); | ||||
|     i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS); | ||||
|     i2c_cmd_link_delete(cmd); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ssd1306_display_text(char* text, uint16_t text_len) | ||||
| { | ||||
|  | ||||
| 	i2c_cmd_handle_t cmd; | ||||
|  | ||||
| 	uint8_t cur_page = 0; | ||||
|  | ||||
| 	cmd = i2c_cmd_link_create(); | ||||
| 	i2c_master_start(cmd); | ||||
| 	i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
|  | ||||
| 	i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); | ||||
| 	i2c_master_write_byte(cmd, 0x00, true); // reset column | ||||
| 	i2c_master_write_byte(cmd, 0x10, true); | ||||
| 	i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page | ||||
|  | ||||
| 	i2c_master_stop(cmd); | ||||
| 	i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); | ||||
| 	i2c_cmd_link_delete(cmd); | ||||
|  | ||||
| 	for (uint8_t i = 0; i < text_len; i++) | ||||
| 	{ | ||||
| 		if (text[i] == '\n') | ||||
| 		{ | ||||
| 			cmd = i2c_cmd_link_create(); | ||||
| 			i2c_master_start(cmd); | ||||
| 			i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
|  | ||||
| 			i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); | ||||
| 			i2c_master_write_byte(cmd, 0x00, true); // reset column | ||||
| 			i2c_master_write_byte(cmd, 0x10, true); | ||||
| 			i2c_master_write_byte(cmd, 0xB0 | ++cur_page, true); // increment page | ||||
|  | ||||
| 			i2c_master_stop(cmd); | ||||
| 			i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); | ||||
| 			i2c_cmd_link_delete(cmd); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			cmd = i2c_cmd_link_create(); | ||||
| 			i2c_master_start(cmd); | ||||
| 			i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); | ||||
|  | ||||
| 			i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); | ||||
| 			i2c_master_write(cmd, font8x8_basic_tr[(uint8_t)text[i]], 8, true); | ||||
|  | ||||
| 			i2c_master_stop(cmd); | ||||
| 			i2c_master_cmd_begin(I2C_NUM, cmd, 10/portTICK_PERIOD_MS); | ||||
| 			i2c_cmd_link_delete(cmd); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void task_ssd1306_display_text(void *pvParameters) | ||||
| { | ||||
| 	char *pcTaskName; | ||||
|   	pcTaskName = (char *) pvParameters; | ||||
|  | ||||
| 	//char text[13] = "Hello world!"; | ||||
| 	//uint8_t text_len = strlen(text); | ||||
|  | ||||
| 	ssd1306_display_text(pcTaskName,  strlen(pcTaskName)); | ||||
|  | ||||
| 	vTaskDelete(NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| 	 | ||||
|  | ||||
							
								
								
									
										65
									
								
								node/main/ssd1366.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								node/main/ssd1366.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| #ifndef MAIN_SSD1366_H_ | ||||
| #define MAIN_SSD1366_H_ | ||||
|  | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "driver/gpio.h" | ||||
| #include "driver/i2c.h" | ||||
| #include "esp_log.h" | ||||
|  | ||||
| // SLA (0x3C) + WRITE_MODE (0x00) =  0x78 (0b01111000) | ||||
| #define OLED_I2C_ADDRESS   0x3C | ||||
|  | ||||
| // Control byte | ||||
| #define OLED_CONTROL_BYTE_CMD_SINGLE    0x80 | ||||
| #define OLED_CONTROL_BYTE_CMD_STREAM    0x00 | ||||
| #define OLED_CONTROL_BYTE_DATA_STREAM   0x40 | ||||
|  | ||||
| // Fundamental commands (pg.28) | ||||
| #define OLED_CMD_SET_CONTRAST           0x81    // follow with 0x7F | ||||
| #define OLED_CMD_DISPLAY_RAM            0xA4 | ||||
| #define OLED_CMD_DISPLAY_ALLON          0xA5 | ||||
| #define OLED_CMD_DISPLAY_NORMAL         0xA6 | ||||
| #define OLED_CMD_DISPLAY_INVERTED       0xA7 | ||||
| #define OLED_CMD_DISPLAY_OFF            0xAE | ||||
| #define OLED_CMD_DISPLAY_ON             0xAF | ||||
|  | ||||
| // Addressing Command Table (pg.30) | ||||
| #define OLED_CMD_SET_MEMORY_ADDR_MODE   0x20    // follow with 0x00 = HORZ mode = Behave like a KS108 graphic LCD | ||||
| #define OLED_CMD_SET_COLUMN_RANGE       0x21    // can be used only in HORZ/VERT mode - follow with 0x00 and 0x7F = COL127 | ||||
| #define OLED_CMD_SET_PAGE_RANGE         0x22    // can be used only in HORZ/VERT mode - follow with 0x00 and 0x07 = PAGE7 | ||||
| #define OLED_CMD_SET_PAGE_ADDR_MODE     0x02    // Page Addressing Mode | ||||
|  | ||||
| // Hardware Config (pg.31) | ||||
| #define OLED_CMD_SET_DISPLAY_START_LINE 0x40 | ||||
| #define OLED_CMD_SET_SEGMENT_REMAP      0xA1     | ||||
| #define OLED_CMD_SET_MUX_RATIO          0xA8    // follow with 0x3F = 64 MUX | ||||
| #define OLED_CMD_SET_COM_SCAN_MODE      0xC8     | ||||
| #define OLED_CMD_SET_DISPLAY_OFFSET     0xD3    // follow with 0x00 | ||||
| #define OLED_CMD_SET_COM_PIN_MAP        0xDA    // follow with 0x12 | ||||
| #define OLED_CMD_NOP                    0xE3    // NOP | ||||
|  | ||||
| // Timing and Driving Scheme (pg.32) | ||||
| #define OLED_CMD_SET_DISPLAY_CLK_DIV    0xD5    // follow with 0x80 | ||||
| #define OLED_CMD_SET_PRECHARGE          0xD9    // follow with 0xF1 | ||||
| #define OLED_CMD_SET_VCOMH_DESELCT      0xDB    // follow with 0x30 | ||||
|  | ||||
| // Charge Pump (pg.62) | ||||
| #define OLED_CMD_SET_CHARGE_PUMP        0x8D    // follow with 0x14 | ||||
|  | ||||
| // Scrolling Command | ||||
| #define OLED_CMD_HORIZONTAL_RIGHT       0x26 | ||||
| #define OLED_CMD_HORIZONTAL_LEFT        0x27 | ||||
| #define OLED_CMD_CONTINUOUS_SCROLL      0x29 | ||||
| #define OLED_CMD_DEACTIVE_SCROLL        0x2E | ||||
| #define OLED_CMD_ACTIVE_SCROLL          0x2F | ||||
| #define OLED_CMD_VERTICAL               0xA3 | ||||
|  | ||||
|  | ||||
| void i2c_master_init(); | ||||
| void ssd1306_init(); | ||||
| void task_ssd1306_display_text(void *pvParameters); | ||||
| void i2c_contrast( int contrast); | ||||
| void ssd1306_display_clear(void); | ||||
| void ssd1306_display_text(char* text, uint16_t text_len); | ||||
|  | ||||
| #endif /* MAIN_SSD1366_H_ */ | ||||
		Reference in New Issue
	
	Block a user