Skip to content
Snippets Groups Projects
Commit e6428c57 authored by Lukas Friedrichsen's avatar Lukas Friedrichsen
Browse files

Bachelorarbeit Lukas Friedrichsen 20170802 (final)

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 737 additions and 0 deletions
File added
File added
File added
File added
File added
File added
KERNEL=="ttyUSB?", SUBSYSTEM=="tty", ACTION=="add", RUN+="/bin/bash service mqtt_node_client restart"
KERNEL=="ttyUSB?", SUBSYSTEM=="tty", ACTION=="remove", RUN+="/bin/bash service mqtt_node_client stop"
This diff is collapsed.
########General settings########
#WiFi interface to use
interface=wlan0
#Driver to use (nl80211 most of the time)
driver=nl80211
#SSID of the access point
ssid=EMRA_Prototype_Network
#WiFi mode (a, b, g or n; setting to g ensures backward compatiblity)
hw_mode=g
#WiFi channel to use (1 - 13; even though this depends on the individual surroundings, high (e.g. 13) and low (e.g. 1) channels tend to have less interferences than the mid-range frequencies)
channel=1
#Options for mac address filtering
#0 - Accept all devices except blacklisted ones (as listed in deny_mac_file)
#1 - Deny all devices except whitelisted ones (as listed in accept_mac_file)
macaddr_acl=0
#deny_mac_file=/etc/hostapd/hostapd.deny
#accept_mac_file=/etc/hostapd/hostapd.accept
#Options for SSID broadcasting
#0 - SSID broadcasting activated
#1 - SSID broadcasting deactivated
ignore_broadcast_ssid=0
#Authentication algorithm to use
#1 - only open system authentication
#2 - both open system authentication and shared key authentication
auth_algs=1
#
#####WPA and WPA2 settings#####
#WPA mode to use
#1 - WPA only
#2 - WPA2 only
#3 - both
wpa=2
#WPA passphrase of the access point
wpa_passphrase=EnergyMeterReadoutAutomation
#WPA key management
wpa_key_mgmt=WPA-PSK
#Security protocol used by WPA
wpa_pairwise=TKIP
#Security protocol used by RSN
rsn_pairwise=CCMP
# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
auto lo
iface lo inet loopback
auto eth0
allow-hotplug eth0
iface eth0 inet manual
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.42.1
netmask 255.255.255.0
network 192.168.42.0
broadcast 192.168.42.255
gateway 192.168.42.1
allow-hotplug wlan1
iface wlan1 inet manual
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example
# Include directory for external configuration-files
include_dir /etc/mosquitto/conf.d
# Location of the PID (process ID) file; keep in sync with
# PIDFILE in /etc/init.d/mosquitto
pid_file /var/run/mosquitto.pid
# System configuration
store_clean_interval 20
sys_interval 15
# Logging
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
log_timestamp true
connection_messages true
# Persistence
persistence true
persistence_location /var/lib/mosquitto/
autosave_interval 900
# Listener
bind_address 192.168.42.1
port 8883
# User authentication
allow_anonymous false
#use_username_as_clientid true
password_file /etc/mosquitto/usr_auth
# Encryption (SSL/TLS)
cafile /etc/mosquitto/ca_certificates/ca_cert.pem
certfile /etc/mosquitto/certs/server_cert.pem
keyfile /etc/mosquitto/certs/server_key.pem
require_certificate false
#!/bin/sh
### BEGIN INIT INFO
# Provides: mqtt_node_client
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start:
# Default-Stop: 0 1 6
# Short-Description: MQTT v3.1 client and Modbus RTU/M-Bus master
# Description:
# This combined implementation of the Python paho-mqtt client, pymodbus and
# python-mbus provides the functionality to act as a gateway between Modbus RTU
# resp. M-Bus devices and an OPC-server via MQTT. The values received from the
# connected devices are logged in the CSV format and published on a MQTT broker
# over WLAN afterwards.
### END INIT INFO
# When this option is enabled, the shell immediately exits if any command fails
set -e
PIDFILE=/var/run/mqtt_node_client.pid
DAEMON=/usr/local/sbin/mqtt_node_client.py
# Does the file exist and is the permission to execute it granted
test -x ${DAEMON} || exit 0
# Set all files to be created from here on to -rw-r--r--
umask 022
# Load init functions
. /lib/lsb/init-functions
# Start the daemon
start() {
log_daemon_msg "Starting daemon:" "mqtt_server_client"
if start-stop-daemon --start --quiet --oknodo --background --make-pidfile --pidfile ${PIDFILE} --startas /bin/bash -- -c "${DAEMON}"; then
log_end_msg 0
else
log_end_msg 1
fi
}
# Stop the daemon
stop() {
log_daemon_msg "Stopping daemon:" "mqtt_server_client"
if start-stop-daemon --stop --quiet --oknodo --pidfile ${PIDFILE}; then
log_end_msg 0
rm -f ${PIDFILE}
else
log_end_msg 1
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status_of_proc -p ${PIDFILE} ${DAEMON} mqtt_server_client && exit 0 || exit $?
;;
*)
log_action_msg "Usage: /etc/init.d/mqtt_server_client {start|stop|restart|status}"
exit 1
esac
exit 0
This diff is collapsed.
#!/bin/sh
### BEGIN INIT INFO
# Provides: mqtt_server_client
# Required-Start: $remote_fs $syslog $network mosquitto
# Required-Stop: $remote_fs $syslog $network mosquitto
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: MQTT v3.1 client
# Description:
# This implementation of the Python paho-mqtt client allows to connect to a
# local MQTT broker and log the data published on definable topics. Furthermore,
# it provides the functionality to act as an interface towards other, non-MQTT
# based applications like e.g. an OPC UA server by generating data-exchange-files
# in the CSV format, containing the most current values published on the
# subscribed topics at all times.
### END INIT INFO
# When this option is on, when any command fails, the shell immediately exits
set -e
PIDFILE=/var/run/mqtt_server_client.pid
DAEMON=/usr/local/sbin/mqtt_server_client.py
# Does the file exist and is the permission to execute it granted
test -x ${DAEMON} || exit 0
# Set all files to be created from here on to -rw-r--r--
umask 022
# Load init functions
. /lib/lsb/init-functions
# Start the daemon
start() {
log_daemon_msg "Starting daemon:" "mqtt_server_client"
if start-stop-daemon --start --quiet --oknodo --background --make-pidfile --pidfile ${PIDFILE} --startas /bin/bash -- -c "${DAEMON}"; then
log_end_msg 0
else
log_end_msg 1
fi
}
# Stop the daemon
stop() {
log_daemon_msg "Stopping daemon:" "mqtt_server_client"
if start-stop-daemon --stop --quiet --oknodo --pidfile ${PIDFILE}; then
log_end_msg 0
rm -f ${PIDFILE}
else
log_end_msg 1
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status_of_proc -p ${PIDFILE} ${DAEMON} mqtt_server_client && exit 0 || exit $?
;;
*)
log_action_msg "Usage: /etc/init.d/mqtt_server_client {start|stop|restart|status}"
exit 1
esac
exit 0
#!/usr/bin/python3
# mqtt_server_client.py
# Copyright 2017 Lukas Friedrichsen
# License: Apache License Version 2.0
#
# 2017-06-01
#
# Description: This implementation of the Python paho-mqtt client allows to
# connect to a MQTT broker and log the data published on definable topics.
# Furthermore, it provides the functionality to act as an interface towards other,
# non-MQTT based applications like e.g. an OPC UA server by generating
# data-exchange-files in the CSV format, containing the most current values
# published on the subscribed topics at all times.
import paho.mqtt.client as mqtt
import time
import ssl
import sys
import os
#------------------------------#
########### Settings ###########
#------------------------------#
# General:
# System paths
_LOG='/var/log/mqtt_server_client/mqtt_server_client.log'
_DB='/var/lib/mqtt_server_client/mqtt_server_client.db.csv'
_EXCHANGE_DIR='/usr/local/var/'
_USER_CREDENTIALS='/usr/local/etc/mqtt_server_client/user_credentials'
_CA='/usr/local/share/ca-certificates/ca_cert.pem'
# MQTT:
# User credentials
with open(_USER_CREDENTIALS, 'r') as user_credentials:
_USERNAME=user_credentials.readline().rstrip('\n')
_PASSWORD=user_credentials.readline().rstrip('\n')
# Topics to subscribe to
_TOPICS='emra/+'
# CSV delimiter
_CSV_DELIMITER=','
# Local IP-address to bind the MQTT client to
_IP_ADDR_LOCAL='127.0.0.1'
# Remote IP-address of the MQTT broker
_IP_ADDR_REMOTE='192.168.42.1'
# Port of the MQTT broker
_MQTT_PORT=8883
# Timeout threshold (in s; maximum period allowed between communications with the
# broker (if no other messages are exchanged, this controls the rate at which the
# client pings the broker)
_MQTT_TIMEOUT=60
#------------------------------#
######## Implementation ########
#------------------------------#
class MQTT_Server_Client(object):
'''
This implementation of the Python paho-mqtt client allows to connect to a
MQTT broker and log the data published on definable topics.
Furthermore, it provides the functionality to act as an interface towards
other, non-MQTT based applications like e.g. an OPC UA server by generating
data-exchange-files in the CSV format, containing the most current values
published on the subscribed topics at all times.
'''
# Initialization method, that is called on the creation of every new client
# instance; initialize needed class variables and set the destination of the
# log- and data-exchange-files
def __init__(self, **kwargs):
'''
Initialization method, that is called on the creation of every new client
instance; initialize needed class variables and set the destination of
the log- and data-exchange-files
Permitted transfer parameters:
- log_file (default: /var/log/mqtt_node_client/mqtt_node_client.log)
- database (default: /var/lib/mqtt_node_client/mqtt_node_client.db.csv)
- exchange_dir (default: /usr/local/var/)
- delimiter (default: ,)
'''
# Evaluate the transfer parameters
self._log = kwargs.get('log_file', '/var/log/mqtt_node_client/mqtt_node_client.log')
self._db = kwargs.get('database', '/var/lib/mqtt_node_client/mqtt_node_client.db.csv')
self._exchange_dir = kwargs.get('exchange_dir', '/usr/local/var/')
self._csv_delimiter = kwargs.get('csv_delimiter', ',')
# Initialize _client
self._client = None
# General:
# Get the current date and time and format the output
# Format: yyyy-mm-dd hh:mm:ss
def get_datetime(self):
'''Get the current date and time and format the output'''
return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
# MQTT:
# Callback function, which is called after an attempt to connect to the MQTT
# broker; evaluate the connection result and, in case of a successfully
# established connection, subscribe the defined topics (reconnection is
# managed by the network loop in any other case)
def _on_connect_cb(self, client_instance, userdata, flags, return_code):
'''Callback function, which is called after an attempt to connect to the MQTT broker'''
log_buffer=(self.get_datetime()+'_on_connect_cb: Return code: '+mqtt.connack_string(return_code)+'\n')
# Connection attempt was successfull
if return_code == mqtt.CONNACK_ACCEPTED:
log_buffer+=(self.get_datetime()+'_on_connect_cb: Subscribing to the defined topics!\n')
# Subscribe to the defined topics; retry every 30 seconds if the
# subscription fails
try:
while (self._client.subscribe(topic=self._topics, qos=1)[0] != mqtt.MQTT_ERR_SUCCESS):
log_buffer+=(self.get_datetime()+'_on_connect_cb: Subscription failed! No connection to the broker! Retrying in 30 seconds!\n')
time.sleep(30)
log_buffer+=(self.get_datetime()+'_on_connect_cb: Successfully subscribed to the defined topics!\n')
except:
log_buffer+=(self.get_datetime()+'_on_connect_cb: Error: '+str(sys.exc_info()[1])+'\n')
# Connection attempt wasn't successfull
else:
log_buffer+=(self.get_datetime()+'_on_connect_cb: Trying again!\n')
# Write the buffer to the log (the usage of a buffer allows to minimalize
# file is opened (and therewith occupied) by the program, thus reducing
# the risk of an access conflict)
with open(self._log, 'a') as log:
log.write(log_buffer)
# Callback function, which is called after the client disconnected the MQTT
# broker; evaluate the connection result and, in case of an intended
# disconnect, exit the program (reconnection is managed by the network loop
# in any other case)
def _on_disconnect_cb(self, client_instance, userdata, return_code):
'''Callback function, which is called after the client disconnected the MQTT broker'''
log_buffer=(self.get_datetime()+' _on_disconnect_cb: Disconnected from the broker! Return code: '+mqtt.error_string(return_code)+'\n')
# Exit the program if the disconnect was caused by client.disconnect()
if return_code == mqtt.MQTT_ERR_SUCCESS:
log_buffer+=(self.get_datetime()+' _on_disconnect_cb: Exiting the program!\n')
# Exit the program
sys.exit()
else:
log_buffer+=(self.get_datetime()+' _on_disconnect_cb: Trying to reconnect!')
# Write the buffer to the log (the usage of a buffer allows to minimalize
# file is opened (and therewith occupied) by the program, thus reducing
# the risk of an access conflict)
with open(self._log, 'a') as log:
log.write(log_buffer)
# Callback function, that is called everytime a new message is published on
# a topic subscribed by the client; log the message received and write it to
# the data-exchange-file
def _on_message_cb(self, client_instance, userdata, msg):
'''Callback function, that is called everytime a new message is published on a topic subscribed by the client'''
log_buffer=(self.get_datetime()+'_on_message_cb: Obtained message '+str(msg.payload).lstrip('b').strip("'")+' on topic '+msg.topic+'\n')
# Write the message received to the database
with open(self._db, 'a') as database:
database.write(self.get_datetime()+self._csv_delimiter+msg.topic[msg.topic.rfind('/')+1:]+self._csv_delimiter+str(msg.payload).lstrip('b').strip("'")+'\n')
try:
# Create the respective sub-directories in the data-exchange-directory
# if they don't exist yet
_exchange_file=self._exchange_dir+msg.topic
os.makedirs(_exchange_file[:_exchange_file.rfind('/')], exist_ok=True)
# Generate a temporary file containing the data received
with open(_exchange_file+'.temp', 'w') as data_exchange_file:
data_exchange_file.write(str(msg.payload).lstrip('b').strip("'"))
data_exchange_file.flush()
os.fsync(data_exchange_file.fileno())
except FileNotFoundError:
# Every then and now, the system cleans up the data-exchange-directory
# and removes outdate files and empty directories. If this garbage
# collector checks on a directory just between os.makedirs(...) and
# open(...), it will only see an empty directory and remove it (a
# wild runtime-condition occurs). The result is a FileNotFoundError.
# In this case, the message received can still be found in the
# database, but the respective data-exchange-file isn't created.
log_buffer+=(self.get_datetime()+'_on_message_cb: Error! No such file or directory: '+_exchange_file+'\n')
except:
log_buffer+=(self.get_datetime()+'_on_message_cb: Error: '+str(sys.exc_info()[1])+'\n')
# Replace the current data-exchange-file with the temporary file
#
# The OPC UA-server constantly tries to read the content from the data-
# exchange-file. So, to avoid complications arising from a simultaneous
# access to the resource, the file has to be edited in an atomic manner
# ("to make the object thread-safe").
# The only real way to achieve this is to write the message to a second
# file and replace the original data-exchange-file by it in one step (by
# editing the object's inode). This is done via the os.rename(...) command.
# According to https://docs.python.org/3/library/os.html:
#
# "If successful, the renaming will be an atomic operation (this is
# a POSIX requirement)."
try:
os.rename(self._exchange_dir+msg.topic+'.temp', self._exchange_dir+msg.topic)
except:
log_buffer+=(self.get_datetime()+'_on_message_cb: Error: '+str(sys.exc_info()[1])+'\n')
# Write the buffer to the log (the usage of a buffer allows to minimalize
# file is opened (and therewith occupied) by the program, thus reducing
# the risk of an access conflict)
with open(self._log, 'a') as log:
log.write(log_buffer)
# Initialize and configure the MQTT client
def mqtt_node_client_init(self, remote_ip, port, topics, local_ip, username, password, **kwargs):
'''
Initialize and configure the MQTT client
Permitted transfer parameters:
- client_id (default: value of username)
- ca (default: None)
- timeout (default: 60)
'''
# Evaluate the transfer parameters
cl_id = kwargs.get('client_id', username)
ca = kwargs.get('ca', None)
timeout = kwargs.get('timeout', 60)
self._topics = topics
with open(self._log, 'a') as log:
log.write(
self.get_datetime()+' mqtt_node_client_init: Initializing and configuring the MQTT client!\n'+
self.get_datetime()+' mqtt_node_client_init: Local IP: '+local_ip+' Remote IP: '+remote_ip+' Port: '+str(port)+'\n'
)
try:
# Initialize the MQTT client and set the respective callback functions
self._client = mqtt.Client(client_id=cl_id, clean_session=False, userdata=None, protocol=mqtt.MQTTv31, transport='tcp')
self._client.on_connect = self._on_connect_cb
self._client.on_disconnect = self._on_disconnect_cb
self._client.on_message = self._on_message_cb
if ca != None:
# Configure the encryption related settings like which TLS version
# to use when communicating with the broker or where to find the
# corresponding CA-certificate
self._client.tls_set(ca_certs=ca, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
# Set username and password
self._client.username_pw_set(username=username, password=password)
# Try to connect to the broker in a non-blocking way and start a
# loop to keep the connection alive afterwards. This network loop also
# automatically handles the reconnection to the broker in case the
# connection is lost without explicitly calling client.disconnect().
self._client.connect_async(host=remote_ip, port=port, keepalive=timeout, bind_address=local_ip)
self._client.loop_forever(retry_first_connection=True)
except:
# Log occuring errors
with open(self._log, 'a') as log:
log.write(self.get_datetime()+' mqtt_node_client_init: Error: '+str(sys.exc_info()[1])+'\n')
# Check, if the MQTT client has already been initialized
if self._client != None:
# Disconnect from the MQTT broker
self._client.disconnect()
else:
# Exit the program directly (instead of from _on_disconnect_cb(...))
sys.exit()
#------------------------------#
######### Main program #########
#------------------------------#
# Create a new instance of MQTT_Node_Client
client = MQTT_Server_Client(log_file=_LOG, database=_DB, exchange_dir=_EXCHANGE_DIR, csv_delimiter=_CSV_DELIMITER)
# Initialize the MQTT-client
client.mqtt_node_client_init(remote_ip=_IP_ADDR_REMOTE, port=_MQTT_PORT, topics=_TOPICS, local_ip=_IP_ADDR_LOCAL, username=_USERNAME, password=_PASSWORD, ca=_CA, timeout=_MQTT_TIMEOUT)
This diff is collapsed.
File added
File added
(* rpi_OPCServer.project
* Copyright 2017 Lukas Friedrichsen
* License: Apache License Version 2.0
*
* 2017-06-08
*
* Description: CODESYS implementation of a basic OPC UA server for the Raspberry
* Pi; serves as the communication interface towards higher level networks
*)
PROGRAM PLC_PRG
VAR CONSTANT
(* Defines *)
MAX_NODE_COUNT: UINT:=10;
END_VAR
VAR
(* Process parameters *)
running: BOOL:=FALSE;
state: UINT:=0;
node_count: UINT:=0;
(* Functions *)
file_op: FILE.Open;
file_rd: FILE.Read;
file_cl: FILE.Close;
(* Files *)
handle_file: CAA.HANDLE;
name_file1: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node1';
name_file2: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node2';
name_file3: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node3';
name_file4: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node4';
name_file5: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node5';
name_file6: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node6';
name_file7: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node7';
name_file8: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node8';
name_file9: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node9';
name_file10: CAA.FILENAME:= '/usr/local/var/emra/rpi_Node10';
(* Variables *)
handle_var_ptr: POINTER TO STRING:=NULL;
opc_node1: STRING(64):='';
opc_node2: STRING(64):='';
opc_node3: STRING(64):='';
opc_node4: STRING(64):='';
opc_node5: STRING(64):='';
opc_node6: STRING(64):='';
opc_node7: STRING(64):='';
opc_node8: STRING(64):='';
opc_node9: STRING(64):='';
opc_node10: STRING(64):='';
END_VAR
________________________________________________________________________________
(* Main program *)
IF NOT running THEN
(* (Re-)Initialize functions and process parameters *)
file_op(xExecute:=FALSE);
file_cl(xExecute:=FALSE);
file_rd(xExecute:=FALSE);
state:=0;
running:=TRUE;
(* Increment node_count until the last file has been reached; begin anew in this case *)
node_count:=node_count+1;
IF node_count<1 OR node_count>MAX_NODE_COUNT THEN
node_count:=1;
END_IF
ELSE
CASE state OF
0:(* Open file *)
CASE node_count OF
(* Choose the file to open as well as the respective variable to write to based on node_count *)
1:
file_op.sFileName:=name_file1;
handle_var_ptr:=ADR(opc_node1);
2:
file_op.sFileName:=name_file2;
handle_var_ptr:=ADR(opc_node2);
3:
file_op.sFileName:=name_file3;
handle_var_ptr:=ADR(opc_node3);
4:
file_op.sFileName:=name_file4;
handle_var_ptr:=ADR(opc_node4);
5:
file_op.sFileName:=name_file5;
handle_var_ptr:=ADR(opc_node5);
6:
file_op.sFileName:=name_file6;
handle_var_ptr:=ADR(opc_node6);
7:
file_op.sFileName:=name_file7;
handle_var_ptr:=ADR(opc_node7);
8:
file_op.sFileName:=name_file8;
handle_var_ptr:=ADR(opc_node8);
9:
file_op.sFileName:=name_file9;
handle_var_ptr:=ADR(opc_node9);
10:
file_op.sFileName:=name_file10;
handle_var_ptr:=ADR(opc_node10);
END_CASE
file_op.eFileMode:=FILE.MODE.MREAD;
file_op.xExclusive:=TRUE;
file_op(xExecute:=TRUE);
IF file_op.xDone THEN
handle_file:=file_op.hFile;
state:=1;
END_IF
IF file_op.xError THEN
(* Set the respective variable's value to -1 if the file couldn't be opened *)
handle_var_ptr^:='-1';
running:=FALSE;
END_IF
1:(* Read file *)
file_rd.hFile:=handle_file;
file_rd.udiTimeOut:=100000; (* 100ms Timeout *)
file_rd.pBuffer:=handle_var_ptr;
file_rd.szBuffer:=SIZEOF(STRING(64));
file_rd(xExecute:=TRUE);
IF file_rd.xDone THEN
state:=2;
END_IF
IF file_rd.xError THEN
(* Set the respective variable's value to -1 if the file couldn't be read *)
handle_var_ptr^:='-1';
(* Don't set running to FALSE here since the file has to be closed again!*)
END_IF
2:(* Close file *)
file_cl.hFile:=handle_file;
file_cl(xExecute:=TRUE);
IF file_cl.xDone THEN
state:=3;
END_IF
3:(* Re-initialize the process variables and functions and increment node_count *)
running:=FALSE;
END_CASE
END_IF
#!/bin/bash
# Subject
SUBJ_BASE="/O=KRONPRINZ GmbH/OU=Innovation Management/emailAddress=lukas.friedrichsen@kronprinz.de"
SUBJ_CA="/CN=EMRA_MQTT_CA_certificate$SUBJ_BASE"
SUBJ_SERVER="/CN=EMRA_MQTT_server_certificate$SUBJ_BASE"
# Generate a temporary file to store the x509_v3 extensions for the server-certificate in since they can't be passed directly via the command line
EXT_TEMP=$(mktemp /tmp/ext_temp.XXX) || { echo "Can't create temporary file!"; exit 1; }
sed -e 's/^.*&&& //' > $EXT_TEMP << EndExtensions
&&& [ Extensions ]
&&& basicConstraints=critical,CA:false
&&& keyUsage=keyEncipherment
&&& extendedKeyUsage=serverAuth
&&& subjectAltName=IP:192.168.42.1,IP:127.0.0.1
EndExtensions
# Remove possible old certificates
echo "Removing possible old certificates!"
sudo rm -f /etc/mosquitto/ca_certificates/ca_*
sudo rm -f /etc/mosquitto/certs/server_*
# CA-certificate
echo "Generating CA-certificate!"
sudo openssl req -x509 -sha256 -newkey rsa:2048 -nodes -keyout /etc/mosquitto/ca_certificates/ca_key.pem -days 3652 -extensions v3_ca -subj "$SUBJ_CA" -out /etc/mosquitto/ca_certificates/ca_cert.pem
sudo chmod 400 /etc/mosquitto/ca_certificates/ca_key.pem
sudo chmod 444 /etc/mosquitto/ca_certificates/ca_cert.pem
# Server-certificate CSR
echo "Generating server-certificate CSR!"
sudo openssl req -sha256 -newkey rsa:2048 -nodes -keyout /etc/mosquitto/certs/server_key.pem -extensions v3_ca -subj "$SUBJ_SERVER" -out /etc/mosquitto/certs/server_cert.csr
sudo chmod 400 /etc/mosquitto/certs/server_key.pem
sudo chown mosquitto /etc/mosquitto/certs/server_key.pem
# Sign server-certificate CSR
echo "Signing server-certificate CSR with the generated CA-certificate!"
sudo openssl x509 -req -in /etc/mosquitto/certs/server_cert.csr -CA /etc/mosquitto/ca_certificates/ca_cert.pem -CAkey /etc/mosquitto/ca_certificates/ca_key.pem -CAcreateserial -days 3652 -extfile $EXT_TEMP -extensions Extensions -out /etc/mosquitto/certs/server_cert.pem
sudo chmod 444 /etc/mosquitto/certs/server_cert.pem
sudo chown mosquitto /etc/mosquitto/certs/server_cert.pem
# Clean up
sudo rm -f /etc/mosquitto/certs/server_cert.csr
rm $EXT_TEMP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment