-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Quick fix to address #64 (needs to be imporved) * Update devContainer.yml * Rework of i2c, network, and openPLC communication * Added try catch for openplc --------- Co-authored-by: Matthias Niedermaier <[email protected]>
- Loading branch information
1 parent
a10fda4
commit e25671a
Showing
3 changed files
with
240 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# hardwareIO.py | ||
# | ||
# This script reads i2c sensor values from the STM32 | ||
# and writes these values to the OpenPLC registers. | ||
# Additionally, the IP address of wlan0 will be transferred | ||
# to the STM32, to show it in the display | ||
|
||
import smbus | ||
import time | ||
from pymodbus.client import ModbusTcpClient | ||
import nmcli | ||
import RPi.GPIO as GPIO | ||
import logging | ||
import threading | ||
|
||
GPIO.setmode(GPIO.BCM) | ||
GPIO.setup(8, GPIO.OUT) # compressor | ||
GPIO.setup(4, GPIO.OUT) # heartbeat | ||
GPIO.setup(7, GPIO.OUT) # systemValve | ||
GPIO.setup(20, GPIO.OUT) # gstSig | ||
GPIO.setup(1, GPIO.IN) # System sensor | ||
GPIO.setup(12, GPIO.IN) # BO sensor | ||
|
||
# I2C channel 1 is connected to the STM32 | ||
channel = 1 | ||
|
||
# The sensor values are stored in address 0x20 | ||
address = 0x20 | ||
|
||
|
||
# Initialize the I2C bus of the RPI | ||
bus = smbus.SMBus(channel) | ||
|
||
gst = 0 # variable for the gas storage tank (GST) | ||
hpt = 0 # variable for the high pressure tank (HPT) | ||
|
||
listIp = [] # IP of the raspberry pi | ||
|
||
id = "unknown" # ID of the STM32 | ||
data = [] # Data received over i2c from the STM32 | ||
dataID = [] # dataID received over i2c from the STM32 | ||
|
||
|
||
|
||
# thread for openplc communication | ||
def thread_openplc(): | ||
attempts = 0 | ||
|
||
# Connect to OpenPLC | ||
client = ModbusTcpClient(host="openplc",port=502) # Create client object | ||
|
||
# Try "10" times to connect to the OpenPLC | ||
logging.info("Trying to connect to OpenPLC") | ||
while attempts < 10: | ||
try: | ||
client.connect() # connect to device, reconnect automatically | ||
logging.info("Connected to OpenPLC within " + str(attempts) + " attempts") | ||
break | ||
except: | ||
attempts += 1 | ||
time.sleep(10) | ||
logging.error("Connection to OpenPLC failed retrying... " + str(attempts) + "/" + "10") | ||
|
||
logging.info("Entering while true in OpenPLC thread") | ||
while True: | ||
global gst | ||
global hpt | ||
global flag | ||
try: | ||
# write GST and HPT to the OpenPLC | ||
client.write_registers(1124,gst) # | ||
client.write_registers(1126,hpt) # | ||
flag = [17273, 25161, 17235, 10349, 12388, 25205, 9257] | ||
client.write_registers(1200,flag) # | ||
except Exception as e: | ||
logging.error("Write to OpenPLC (GST|HPT|FLAG) failed - " + str(e)) | ||
|
||
# read coils from OpenPLC | ||
try: | ||
plcCoils=client.read_coils(0,4) | ||
GPIO.output(4, plcCoils.bits[0]) # heartbeat | ||
GPIO.output(8, plcCoils.bits[1]) # compressor | ||
GPIO.output(7, plcCoils.bits[2]) # systemValve | ||
GPIO.output(20, plcCoils.bits[3]) # gstSig | ||
except Exception as e: | ||
logging.error("Read from OpenPLC failed - " + str(e)) | ||
|
||
# write input register to OpenPLC | ||
try: | ||
client.write_registers(1132,GPIO.input(1)) # System sensor | ||
client.write_registers(1134,GPIO.input(12)) # BO sensor | ||
except Exception as e: | ||
logging.error("Write to OpenPLC failed - " + str(e)) | ||
|
||
time.sleep(0.02) # OpenPLC has a Cycle time of 50ms | ||
|
||
# Should never be reached | ||
client.close() # Disconnect device | ||
|
||
# thread for network connection | ||
def thread_network(): | ||
global dataID | ||
global ssid | ||
global id | ||
global listIp | ||
|
||
# Getting current connection | ||
try: | ||
current_connection = "" | ||
nmcli.disable_use_sudo() | ||
for conn in nmcli.connection(): | ||
if conn.device == 'wlan0': | ||
current_connection = conn.name | ||
break | ||
except Exception as e: | ||
logging.error("Error getting current connection... " + str(e)) | ||
|
||
try: | ||
current_ssid = nmcli.connection.show('cybics')["802-11-wireless.ssid"] | ||
logging.info(f"Current connection: {current_connection}, ap ssid: {current_ssid}") | ||
except Exception as e: | ||
logging.error("No current connection " + str(e)) | ||
|
||
logging.info("Entering while true in network thread") | ||
while True: | ||
try: | ||
# Get IP address of wlan0 | ||
ip = nmcli.device.show('wlan0').get('IP4.ADDRESS[1]', "unknown") | ||
ip = ip.split('/')[0] # remove the network CIDR suffix | ||
listIp = list(ip) | ||
|
||
|
||
|
||
except Exception as e: | ||
logging.error("Error in getting IP of wlan0 - " + str(e)) | ||
|
||
# Simple check, if correct dataID was received | ||
if dataID[12] in ['0', '1']: | ||
ssid = f"cybics-{id}" | ||
if current_ssid != ssid: | ||
try: | ||
logging.info(f"Configure ssid {ssid}") | ||
nmcli.connection.modify('cybics', {'wifi.ssid': ssid}) | ||
current_ssid = ssid | ||
except Exception as e: | ||
logging.error("Configure ssid failed - " + str(e)) | ||
time.sleep(1) | ||
|
||
connection = 'cybics' if dataID[12] == '1' else 'preconfigured' | ||
if current_connection != connection: | ||
try: | ||
logging.info(f"Enable connection {connection}") | ||
nmcli.connection.up(connection, 0) # do not wait for connection | ||
logging.info(f"Enable connection - " + str(nmcli.connection.show(connection))) | ||
current_connection = connection | ||
except Exception as e: | ||
logging.error("Enable connection failed - " + str(e)) | ||
time.sleep(1) | ||
|
||
logging.debug("End of while true thread_network") | ||
time.sleep(1) | ||
|
||
# thread for i2c communication | ||
def thread_i2c(): | ||
global gst | ||
global hpt | ||
global flag | ||
global id | ||
global data | ||
global dataID | ||
global listIp | ||
global bus | ||
|
||
logging.info("Entering while true in i2c thread") | ||
while True: | ||
try: | ||
# Read the values for GST and HPT | ||
data = bus.read_i2c_block_data(address, 0x00, 20) | ||
# print(data) | ||
for row in range(len(data)): | ||
data[row] = chr(data[row]) | ||
logging.debug("Read over i2c: " + str(data)) | ||
|
||
# Format the IP and send it via i2c to the RPI | ||
sendIP = ['I', 'P',':'] + listIp | ||
for row in range(len(sendIP)): | ||
sendIP[row] = ord(sendIP[row]) | ||
bus.write_i2c_block_data(address, 0x00, sendIP) | ||
|
||
# Simple check, if correct data was received | ||
if(str(data[0]) == "G" and str(data[1]) == "S" and str(data[2]) == "T"): | ||
gst = int(str(data[5] + data[6] + data[7])) | ||
hpt = int(str(data[14] + data[15] + data[16])) | ||
|
||
logging.debug(f"Setting GST to {str(gst)} and HPT to {str(hpt)}") | ||
|
||
# Read STM32 ID Code | ||
data = bus.read_i2c_block_data(address, 0x01, 13) | ||
for c in range(len(data)): | ||
data[c] = chr(data[c]) | ||
#id=str(c-"a" for c in id) | ||
data="".join(data) | ||
dataID=data | ||
id = data[:12] | ||
|
||
time.sleep(0.02) # OpenPLC has a Cycle time of 50ms | ||
|
||
except Exception as e: | ||
logging.error("Error in read i2c - retrying in 1 sec: " + str(e)) | ||
time.sleep(1) | ||
|
||
|
||
# main function | ||
if __name__ == "__main__": | ||
format = "%(asctime)s: %(message)s" | ||
logging.basicConfig(format=format, level=logging.INFO, | ||
datefmt="%H:%M:%S") | ||
|
||
logging.info("Main : before creating threads") | ||
openplcX = threading.Thread(target=thread_openplc, args=()) | ||
i2cX = threading.Thread(target=thread_i2c, args=()) | ||
networkX = threading.Thread(target=thread_network, args=()) | ||
logging.info("Main : before running threads") | ||
openplcX.start() | ||
i2cX.start() | ||
networkX.start() | ||
logging.info("Main : after starting threads") | ||
|
||
# Continuously check if threads are active | ||
while openplcX.is_alive() or i2cX.is_alive() or networkX.is_alive(): | ||
logging.info(f"Main : openplcX is {'alive' if openplcX.is_alive() else 'not alive'}") | ||
logging.info(f"Main : i2cX is {'alive' if i2cX.is_alive() else 'not alive'}") | ||
logging.info(f"Main : networkX is {'alive' if networkX.is_alive() else 'not alive'}") | ||
time.sleep(30) # Check every 30 second | ||
|
||
logging.error(f"Main : Something went horrible wrong. Should not reach this.") |
Oops, something went wrong.