Upgrade to 1.5.2, tooling for VPN API requests

This commit is contained in:
Quentin WEPHRE
2024-07-19 08:59:28 +02:00
parent 5819418f7c
commit 1a383c5302
25 changed files with 2026 additions and 1835 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
I-Sight_Generated_Files*
DATAMODEL_*

View File

@@ -1,21 +1,21 @@
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will execute a Direct Method for the ThingsPro module on the devices. This Direct Method enable the Discovery Service.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
devices=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND capabilities.iotEdge = true" --output json)
device_ids=$(echo "$devices" | jq -r '.[].deviceId')
for device_id in $device_ids
do
echo "$device_id"
az iot hub invoke-module-method --method-name thingspro-api-v1 --method-payload "{\"method\":\"PUT\",\"path\":\"/system/discovery\",\"requestBody\":{\"enable\": true}""}" --device-id $device_id --module-id thingspro-agent --hub-name $iothub_name
done
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will execute a Direct Method for the ThingsPro module on the devices. This Direct Method enable the Discovery Service.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
devices=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND capabilities.iotEdge = true" --output json)
device_ids=$(echo "$devices" | jq -r '.[].deviceId')
for device_id in $device_ids
do
echo "$device_id"
az iot hub invoke-module-method --method-name thingspro-api-v1 --method-payload "{\"method\":\"PUT\",\"path\":\"/system/discovery\",\"requestBody\":{\"enable\": true}""}" --device-id $device_id --module-id thingspro-agent --hub-name $iothub_name
done

View File

@@ -1,23 +1,23 @@
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will configure the modules of all the IoT Edge devices of Danish (as Danish have up to 29 devices) with the given template.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
json_output=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND tags.number != '30' AND capabilities.iotEdge = true" --output json)
hashmap=$(echo "$json_output" | jq -r 'map({key: .tags.number, value: .deviceId}) | from_entries')
for key in $(echo "$hashmap" | jq -r 'keys | map(tonumber) | sort_by(.) | .[]'); do
value=$(jq -r --arg k "$key" '.[$k]' <<< "$hashmap")
az iot edge set-modules --device-id $value --hub-name $iothub_name --content moxa_ac_template_1.5_patch.json
done
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will configure the modules of all the IoT Edge devices of Danish (as Danish have up to 29 devices) with the given template.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
json_output=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND tags.number != '30' AND capabilities.iotEdge = true" --output json)
hashmap=$(echo "$json_output" | jq -r 'map({key: .tags.number, value: .deviceId}) | from_entries')
for key in $(echo "$hashmap" | jq -r 'keys | map(tonumber) | sort_by(.) | .[]'); do
value=$(jq -r --arg k "$key" '.[$k]' <<< "$hashmap")
az iot edge set-modules --device-id $value --hub-name $iothub_name --content moxa_ac_template_1.5_patch.json
done
echo $hashmap

View File

@@ -1,23 +1,23 @@
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will execute a Direct Method for the ThingsPro module on the devices.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
json_output=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND (tags.number = '6' OR tags.number = '8' OR tags.number = '12' OR tags.number = '13') AND capabilities.iotEdge = true" --output json)
hashmap=$(echo "$json_output" | jq -r 'map({key: .tags.number, value: .deviceId}) | from_entries')
for key in $(echo "$hashmap" | jq -r 'keys | map(tonumber) | sort_by(.) | .[]'); do
value=$(jq -r --arg k "$key" '.[$k]' <<< "$hashmap")
status=$(az iot hub invoke-module-method --timeout 10 --method-name thingspro-api-v1 --method-payload '{"method":"GET","path":"/device/general"}' --device-id $value --module-id thingspro-agent --hub-name $iothub_name | jq .status)
echo "Key: $key, Value: $value, Status: $status"
done
#echo $hashmap
#!/bin/bash
# Get all devices from an IoT Hub (iothub_name) that have the given tag (tag_key == tag_value)
# Can also filter using tags.number
# Execute an Azure command for each of the devices found
# Here the command will execute a Direct Method for the ThingsPro module on the devices.
iothub_name="IotHub-CUBE-Prod"
tag_key="site"
tag_value="DANISH"
json_output=$(az iot hub query --hub-name $iothub_name --query-command "SELECT * FROM devices WHERE tags.$tag_key = '$tag_value' AND (tags.number = '6' OR tags.number = '8' OR tags.number = '12' OR tags.number = '13') AND capabilities.iotEdge = true" --output json)
hashmap=$(echo "$json_output" | jq -r 'map({key: .tags.number, value: .deviceId}) | from_entries')
for key in $(echo "$hashmap" | jq -r 'keys | map(tonumber) | sort_by(.) | .[]'); do
value=$(jq -r --arg k "$key" '.[$k]' <<< "$hashmap")
status=$(az iot hub invoke-module-method --timeout 10 --method-name thingspro-api-v1 --method-payload '{"method":"GET","path":"/device/general"}' --device-id $value --module-id thingspro-agent --hub-name $iothub_name | jq .status)
echo "Key: $key, Value: $value, Status: $status"
done
#echo $hashmap

View File

@@ -1,84 +1,84 @@
import pandas as pd
import subprocess
import argparse
import sys
import json
# This Python script will read an Excel file containing a list of devices for a site (using --serials *file name*)
# It will then create a IoT Edge device for each of the line in the file
# The user need to precise which IoT Hub is used (using --env *PROD or DEV*)
# The user need provide the site name, which will be added as a tag (using --site *site name*)
# The user need to precise which configuration of the modules should be used, according to the running firmware on the devices (using --version *version number*)
# Example:
# python create_devices_list.py --serials DANISH.xlsx --env PROD --site DANISH --version 1.5_patch
# will create all the IoT Edge devices using the serial number found in the DANISH.xlsx file
# on the PROD IoT Hub
# tag each new device with a site = DANISH
# configure the modules for each devices with the corresponding version found in moxa_ac_template_1.5_patch.json
# each device will have also be given a number = i where i is incremented automatically according to the number of device in the Excel file
# the provided Excel file will be modified, adding a column connection_string for each of the devices created with their corresponding connection string
# the output is therefore SENSITIVE
def generate_commands(serials_file, env, site, version):
# Read serial numbers from Excel file
df = pd.read_excel(serials_file)
df = df[df['device_name'].notnull()]
serials = df['device_name'].tolist()
# Initialize number
number = 1
# List to store connection strings
connection_strings = []
# Generate commands for each serial number
for serial in serials:
# Replace placeholders with actual values
print(serial, end=" ")
device_id = f"DIGIT-{serial}"
print(device_id, end=" ")
tags = f'{{"deviceId":"{device_id}","site":"{site}","number":"{number}"}}'
content = f"moxa_ac_template_{version}.json"
# Construct command strings
create_command = f"az iot hub device-identity create --device-id {device_id} --hub-name IotHub-CUBE-{env} --edge-enabled"
twin_update_command = f"az iot hub device-twin update --device-id {device_id} --hub-name IotHub-CUBE-{env} --set tags='{tags}'"
set_modules_command = f"az iot edge set-modules --device-id {device_id} --hub-name IotHub-CUBE-{env} --content {content}"
# Execute create command and get primary key
create_output = subprocess.check_output(create_command, shell=True)
create_output_json = json.loads(create_output.decode('utf-8'))
primary_key = create_output_json['authentication']['symmetricKey']['primaryKey']
print(primary_key, end=" ")
# Generate connection string
connection_string = f"HostName=IotHub-CUBE-{env}.azure-devices.net;DeviceId={device_id};SharedAccessKey={primary_key}"
print(connection_string)
connection_strings.append(connection_string)
tags_output = subprocess.run(twin_update_command, shell=True)
modules_output = subprocess.run(set_modules_command, shell=True)
# Increment number
number += 1
# Add connection strings to DataFrame
df['connection_string'] = connection_strings
# Save DataFrame to Excel file
df.to_excel(serials_file, index=False)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Create devices list')
parser.add_argument('--serials', required=True, help='Excel file containing serial numbers')
parser.add_argument('--env', required=True, help='Environment (PROD or DEV)')
parser.add_argument('--site', required=True, help='Site name')
parser.add_argument('--version', required=True, help='Version number')
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# Generate commands
generate_commands(args.serials, args.env, args.site, args.version)
import pandas as pd
import subprocess
import argparse
import sys
import json
# This Python script will read an Excel file containing a list of devices for a site (using --serials *file name*)
# It will then create a IoT Edge device for each of the line in the file
# The user need to precise which IoT Hub is used (using --env *PROD or DEV*)
# The user need provide the site name, which will be added as a tag (using --site *site name*)
# The user need to precise which configuration of the modules should be used, according to the running firmware on the devices (using --version *version number*)
# Example:
# python create_devices_list.py --serials DANISH.xlsx --env PROD --site DANISH --version 1.5_patch
# will create all the IoT Edge devices using the serial number found in the DANISH.xlsx file
# on the PROD IoT Hub
# tag each new device with a site = DANISH
# configure the modules for each devices with the corresponding version found in moxa_ac_template_1.5_patch.json
# each device will have also be given a number = i where i is incremented automatically according to the number of device in the Excel file
# the provided Excel file will be modified, adding a column connection_string for each of the devices created with their corresponding connection string
# the output is therefore SENSITIVE
def generate_commands(serials_file, env, site, version):
# Read serial numbers from Excel file
df = pd.read_excel(serials_file)
df = df[df['device_name'].notnull()]
serials = df['device_name'].tolist()
# Initialize number
number = 1
# List to store connection strings
connection_strings = []
# Generate commands for each serial number
for serial in serials:
# Replace placeholders with actual values
print(serial, end=" ")
device_id = f"DIGIT-{serial}"
print(device_id, end=" ")
tags = f'{{"deviceId":"{device_id}","site":"{site}","number":"{number}"}}'
content = f"moxa_ac_template_{version}.json"
# Construct command strings
create_command = f"az iot hub device-identity create --device-id {device_id} --hub-name IotHub-CUBE-{env} --edge-enabled"
twin_update_command = f"az iot hub device-twin update --device-id {device_id} --hub-name IotHub-CUBE-{env} --set tags='{tags}'"
set_modules_command = f"az iot edge set-modules --device-id {device_id} --hub-name IotHub-CUBE-{env} --content {content}"
# Execute create command and get primary key
create_output = subprocess.check_output(create_command, shell=True)
create_output_json = json.loads(create_output.decode('utf-8'))
primary_key = create_output_json['authentication']['symmetricKey']['primaryKey']
print(primary_key, end=" ")
# Generate connection string
connection_string = f"HostName=IotHub-CUBE-{env}.azure-devices.net;DeviceId={device_id};SharedAccessKey={primary_key}"
print(connection_string)
connection_strings.append(connection_string)
tags_output = subprocess.run(twin_update_command, shell=True)
modules_output = subprocess.run(set_modules_command, shell=True)
# Increment number
number += 1
# Add connection strings to DataFrame
df['connection_string'] = connection_strings
# Save DataFrame to Excel file
df.to_excel(serials_file, index=False)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Create devices list')
parser.add_argument('--serials', required=True, help='Excel file containing serial numbers')
parser.add_argument('--env', required=True, help='Environment (PROD or DEV)')
parser.add_argument('--site', required=True, help='Site name')
parser.add_argument('--version', required=True, help='Version number')
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# Generate commands
generate_commands(args.serials, args.env, args.site, args.version)

View File

@@ -1,48 +1,48 @@
import pandas as pd
import subprocess
import argparse
import sys
import json
# This Python script will create an IoT Edge device according to the provided parameters
# It will create the device with the name DIGIT-*serial number* (using --serial *serial number*)
# The user need to precise the number of the gateway on the site (using --number *number*)
# The user need to precise which IoT Hub is used (using --env *PROD or DEV*)
# The user need provide the site name, which will be added as a tag (using --site *site name*)
# The user need to precise which configuration of the modules should be used, according to the running firmware on the device (using --version *version number*)
# Example:
# python create_moxa.py --serial TBBHB1044382 --number 5 --env PROD --site DANISH --version 1.5_patch
# will create the IoT Edge device using the serial number provided (TBBHB1044382)
# on the PROD IoT Hub
# tag the device with number = 5
# tag the device with site = DANISH
# configure the modules for the device with the corresponding version found in moxa_ac_template_1.5_patch.json
def generate_commands(serial, number, env, site, version):
device_id = f"DIGIT-{serial}"
tags = f'{{"deviceId":"{device_id}","site":"{site}","number":"{number}"}}'
content = f"moxa_ac_template_{version}.json"
create_device_command = f"az iot hub device-identity create --device-id {device_id} --hub-name IotHub-CUBE-{env} --edge-enabled"
twin_update_command = f"az iot hub device-twin update --device-id {device_id} --hub-name IotHub-CUBE-{env} --set tags='{tags}'"
set_modules_command = f"az iot edge set-modules --device-id {device_id} --hub-name IotHub-CUBE-{env} --content {content}"
subprocess.run(create_device_command, shell=True)
subprocess.run(twin_update_command, shell=True)
subprocess.run(set_modules_command, shell=True)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Create devices list')
parser.add_argument('--serial', required=True, help='Serial number of the gateway')
parser.add_argument('--number', required=True, help='Gateway on-site number')
parser.add_argument('--env', required=True, help='Environment (PROD or DEV)')
parser.add_argument('--site', required=True, help='Site name')
parser.add_argument('--version', required=True, help='Version number')
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# Generate commands
generate_commands(args.serial, args.number, args.env, args.site, args.version)
import pandas as pd
import subprocess
import argparse
import sys
import json
# This Python script will create an IoT Edge device according to the provided parameters
# It will create the device with the name DIGIT-*serial number* (using --serial *serial number*)
# The user need to precise the number of the gateway on the site (using --number *number*)
# The user need to precise which IoT Hub is used (using --env *PROD or DEV*)
# The user need provide the site name, which will be added as a tag (using --site *site name*)
# The user need to precise which configuration of the modules should be used, according to the running firmware on the device (using --version *version number*)
# Example:
# python create_moxa.py --serial TBBHB1044382 --number 5 --env PROD --site DANISH --version 1.5_patch
# will create the IoT Edge device using the serial number provided (TBBHB1044382)
# on the PROD IoT Hub
# tag the device with number = 5
# tag the device with site = DANISH
# configure the modules for the device with the corresponding version found in moxa_ac_template_1.5_patch.json
def generate_commands(serial, number, env, site, version):
device_id = f"DIGIT-{serial}"
tags = f'{{"deviceId":"{device_id}","site":"{site}","number":"{number}"}}'
content = f"moxa_ac_template_{version}.json"
create_device_command = f"az iot hub device-identity create --device-id {device_id} --hub-name IotHub-CUBE-{env} --edge-enabled"
twin_update_command = f"az iot hub device-twin update --device-id {device_id} --hub-name IotHub-CUBE-{env} --set tags='{tags}'"
set_modules_command = f"az iot edge set-modules --device-id {device_id} --hub-name IotHub-CUBE-{env} --content {content}"
subprocess.run(create_device_command, shell=True)
subprocess.run(twin_update_command, shell=True)
subprocess.run(set_modules_command, shell=True)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description='Create devices list')
parser.add_argument('--serial', required=True, help='Serial number of the gateway')
parser.add_argument('--number', required=True, help='Gateway on-site number')
parser.add_argument('--env', required=True, help='Environment (PROD or DEV)')
parser.add_argument('--site', required=True, help='Site name')
parser.add_argument('--version', required=True, help='Version number')
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
# Generate commands
generate_commands(args.serial, args.number, args.env, args.site, args.version)

View File

@@ -1,5 +1,5 @@
az iot hub device-identity create --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-PROD --edge-enabled
az iot hub device-twin update --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-PROD --set tags='{"deviceId":"DIGIT-TBBHB1044382","site":"SASK","number":"1"}'
az iot edge set-modules --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-DEV --content moxa_ac_template.json
az iot hub device-identity create --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-PROD --edge-enabled
az iot hub device-twin update --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-PROD --set tags='{"deviceId":"DIGIT-TBBHB1044382","site":"SASK","number":"1"}'
az iot edge set-modules --device-id DIGIT-TBBHB1044382 --hub-name IotHub-CUBE-DEV --content moxa_ac_template.json
This file is a just a note for usual Azure commands involved to create a device.

View File

@@ -1,71 +1,71 @@
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.1.1-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.1.1-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}

View File

@@ -1,71 +1,71 @@
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.1.4",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.1.4",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.1.4",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.1.4",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}

View File

@@ -1,71 +1,71 @@
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.2.7",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.2.7",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.2.7",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.2.7",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}

View File

@@ -1,71 +1,71 @@
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.4.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.4.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.4.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.4.10",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.3-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/cloud/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}

View File

@@ -1,71 +1,71 @@
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.4.27",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.4.27",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.5-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/azureiotedge/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}
{
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.1",
"runtime": {
"type": "docker",
"settings": {}
},
"systemModules": {
"edgeAgent": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
},
"SendRuntimeQualityTelemetry": {
"value": false
}
},
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.4.27",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}}}}"
},
"type": "docker"
},
"edgeHub": {
"env": {
"UpstreamProtocol": {
"value": "AMQPWS"
}
},
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.4.27",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
},
"status": "running",
"type": "docker"
}
},
"modules": {
"thingspro-agent": {
"restartPolicy": "always",
"settings": {
"image": "moxa2019/thingspro-agent:2.2.5-armhf",
"createOptions": "{\"HostConfig\":{\"LogConfig\":{\"Type\":\"json-file\",\"Config\":{\"max-size\":\"10m\",\"max-file\":\"3\"}},\"Binds\":[\"/var/thingspro/apps/azureiotedge/data/setting/:/var/thingspro/cloud/setting/\",\"/run/:/host/run/\",\"/var/thingspro/data/:/var/thingspro/data/\"]}}"
},
"status": "running",
"type": "docker"
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.1",
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
},
"routes": {
"route": {
"route": "FROM /messages/* INTO $upstream"
}
}
}
},
"thingspro-agent": {
"properties.desired": {}
}
}
}

View File

@@ -1,23 +1,23 @@
MIT License
Copyright (c) 2023 Amjad Badar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2023 Amjad Badar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Original code modified 2024 Quentin WEPHRE

View File

@@ -1,95 +1,95 @@
# ORIGINAL README FROM MOXA
# COMPLETELY OUTDATED AS OF 06/2024
# DOES NOT WORK WITH CURRENT VERSION
# KEPT FOR INFORMATION AND HISTORICAL DATA
## Moxa AIG-301- Data Path Configuration
## Pre-requisites
The following two Excel files from Saft are required
- [ ] 0000123704_SAFT_Generic_Data_Model.xlsx
- [ ] I-Sight_Project_Communication_Network_Config.xlsx
Python Script to generate shell sript from Execel files
data_path_config.py
Note: The python script and the excel files must be kept in the same directory. The files generated by the python script will be present inside the "Generated_Files" folder.
Also, make sure the data provided in the Excel sheet is correct. Else it can affect the configuration process.
## Step1
- [ ] The Python Version used for the project development is:
'''
3.10.9
'''
- [ ] Install all dependencies of the python by running following command:
```
sudo pip3 install -r requirements.txt
```
- [ ] Execute python script in the directory where Execl files are located
```
python3 data_path_config.py
```
OUTPUT:
On successfull execution of the script, it generates the folder "Generated_Files". The folder contains:
1. data_path_configuration_shell_script.sh
2. data_config_debug.log
The "data_path_configuration_shell_script.sh" is the script that needs to be executed in the Moxa device for configuring the ThingsPro Edge software.
The "data_config_debug.log" is the log file generated after running the python script and it performs some basic error checks on the given excel files.
## Step2
- [ ] Copy shell script into Moxa gateway in home directory via File Transfer tool example [winscp](https://winscp.net/download/WinSCP-5.21.7-Setup.exe) files
## Step3
- [ ] Change file mode of shell script to make it executable by executing the following commands:
```
sudo sed -i -e 's/\r$//' data_path_configuration_shell_script.sh
sudo chmod +x data_path_configuration_shell_script.sh
```
## Step4
- [ ] Execute shell script in root directory, otheriwse tpfunc will not deployed
```
sudo su
```
```
./data_path_configuration_shell_script.sh
```
## Step5
- [ ] A log report "data_shell_script.log" is generated in the same directory after executing the shell script "data_path_configuration_shell_script.sh". This log report provides information on whether the commands of the shell script were successful or not based on HTTP status codes. Some most common HTTP requests from the log are:
```
HTTP request 200 or 201 means that command was successfully executed
HTTP request 400 and above means that the command was NOT executed successfully
```
Note: An HTTP request of 400 and above can either mean that the data (which is obtained from the provided excel sheets) within the command is Incorrect or that the ThingsPro Edge software is already configured with that data.
- [ ] Verify results on ThingsPro Edge webGUI
1) Check Modbus Configuration
2) Check Azure IoT Edge Telemetry
- A seperate topic will be created for each slave
3) Tpfunc under Function
## Additional Information
The "Generated_Files" folder in this repository was created by running the python script with the excel sheets in the same repository. It can be used for reference.
The Folder "Screenshots" has images that can be used for reference.
Also, each data model in "0000123704_SAFT_Generic_Data_Model.xlsx" file needs to be modified to include an additional column that provides information regarding which commands must be configured for TP function as shown in the screenshot below:
![Screenshot](Screenshots/tpfunc.png)
# ORIGINAL README FROM MOXA
# COMPLETELY OUTDATED AS OF 06/2024
# DOES NOT WORK WITH CURRENT VERSION
# KEPT FOR INFORMATION AND HISTORICAL DATA
## Moxa AIG-301- Data Path Configuration
## Pre-requisites
The following two Excel files from Saft are required
- [ ] 0000123704_SAFT_Generic_Data_Model.xlsx
- [ ] I-Sight_Project_Communication_Network_Config.xlsx
Python Script to generate shell sript from Execel files
data_path_config.py
Note: The python script and the excel files must be kept in the same directory. The files generated by the python script will be present inside the "Generated_Files" folder.
Also, make sure the data provided in the Excel sheet is correct. Else it can affect the configuration process.
## Step1
- [ ] The Python Version used for the project development is:
'''
3.10.9
'''
- [ ] Install all dependencies of the python by running following command:
```
sudo pip3 install -r requirements.txt
```
- [ ] Execute python script in the directory where Execl files are located
```
python3 data_path_config.py
```
OUTPUT:
On successfull execution of the script, it generates the folder "Generated_Files". The folder contains:
1. data_path_configuration_shell_script.sh
2. data_config_debug.log
The "data_path_configuration_shell_script.sh" is the script that needs to be executed in the Moxa device for configuring the ThingsPro Edge software.
The "data_config_debug.log" is the log file generated after running the python script and it performs some basic error checks on the given excel files.
## Step2
- [ ] Copy shell script into Moxa gateway in home directory via File Transfer tool example [winscp](https://winscp.net/download/WinSCP-5.21.7-Setup.exe) files
## Step3
- [ ] Change file mode of shell script to make it executable by executing the following commands:
```
sudo sed -i -e 's/\r$//' data_path_configuration_shell_script.sh
sudo chmod +x data_path_configuration_shell_script.sh
```
## Step4
- [ ] Execute shell script in root directory, otheriwse tpfunc will not deployed
```
sudo su
```
```
./data_path_configuration_shell_script.sh
```
## Step5
- [ ] A log report "data_shell_script.log" is generated in the same directory after executing the shell script "data_path_configuration_shell_script.sh". This log report provides information on whether the commands of the shell script were successful or not based on HTTP status codes. Some most common HTTP requests from the log are:
```
HTTP request 200 or 201 means that command was successfully executed
HTTP request 400 and above means that the command was NOT executed successfully
```
Note: An HTTP request of 400 and above can either mean that the data (which is obtained from the provided excel sheets) within the command is Incorrect or that the ThingsPro Edge software is already configured with that data.
- [ ] Verify results on ThingsPro Edge webGUI
1) Check Modbus Configuration
2) Check Azure IoT Edge Telemetry
- A seperate topic will be created for each slave
3) Tpfunc under Function
## Additional Information
The "Generated_Files" folder in this repository was created by running the python script with the excel sheets in the same repository. It can be used for reference.
The Folder "Screenshots" has images that can be used for reference.
Also, each data model in "0000123704_SAFT_Generic_Data_Model.xlsx" file needs to be modified to include an additional column that provides information regarding which commands must be configured for TP function as shown in the screenshot below:
![Screenshot](Screenshots/tpfunc.png)

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
pandas==1.4.3
openpyxl==3.1.0
pandas==1.4.3
openpyxl==3.1.0

View File

@@ -1,45 +1,49 @@
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.protocol.models import QuerySpecification
from azure.iot.hub.models import CloudToDeviceMethod, CloudToDeviceMethodResult
import json
module_id = "thingspro-agent"
method_name = "thingspro-api-v1"
payload = '{"method":"GET", "path":"/device/general"}'
# Install the Azure IoT Hub SDK:
# pip install azure-iot-hub
# Authenticate to your Azure account
CONNECTION_STRING = "HostName=IotHub-CUBE-PROD.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey= ..."
if CONNECTION_STRING == "":
print("Provide a connection string for the Iot Hub before running the script!")
exit(13)
registry_manager = IoTHubRegistryManager.from_connection_string(CONNECTION_STRING)
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE tags.site != 'QWE' AND tags.number != '0' AND capabilities.iotEdge = true")
query_result = registry_manager.query_iot_hub(query_spec)
devices = []
for item in query_result.items:
devices.append([int(item.tags['number']), item.tags['deviceId'], item.tags['site']])
ordered_devices = sorted(devices, key = lambda x: (x[2], x[0]))
for i in ordered_devices:
current_device_modules = registry_manager.get_modules(i[1])
for module in current_device_modules:
if module.module_id == module_id:
thingspro_module = module
if thingspro_module:
#print("Found thingspro-agent for " + i[1] + " (" + i[2] + ")")
try:
direct_method = CloudToDeviceMethod(method_name=method_name, payload=json.loads(payload))
response = registry_manager.invoke_device_module_method(device_id=i[1], module_id=module_id, direct_method_request=direct_method)
print(str(i[2]), str(i[0]), str(i[1]), response.payload['data']['description'],sep=";")
except:
print(str(i[2]), str(i[0]), str(i[1]), "UNREACHABLE",sep=";")
else:
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.protocol.models import QuerySpecification
from azure.iot.hub.models import CloudToDeviceMethod, CloudToDeviceMethodResult
import json
module_id = "thingspro-agent"
method_name = "thingspro-api-v1"
payload = '{"method":"GET", "path":"/device/general"}'
# Install the Azure IoT Hub SDK:
# pip install azure-iot-hub
# Authenticate to your Azure account
CONNECTION_STRING = "HostName=IotHub-CUBE-PROD.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=...="
if CONNECTION_STRING == "":
print("Provide a connection string for the Iot Hub before running the script!")
exit(13)
registry_manager = IoTHubRegistryManager.from_connection_string(CONNECTION_STRING)
query_spec = QuerySpecification(query="SELECT * FROM devices WHERE tags.site = 'MYRTLE' AND tags.number != '0' AND capabilities.iotEdge = true")
query_result = registry_manager.query_iot_hub(query_spec)
devices = []
for item in query_result.items:
devices.append([int(item.tags['number']), item.tags['deviceId'], item.tags['site']])
ordered_devices = sorted(devices, key = lambda x: (x[2], x[0]))
for i in ordered_devices:
current_device_modules = registry_manager.get_modules(i[1])
for module in current_device_modules:
if module.module_id == module_id:
thingspro_module = module
if thingspro_module:
#print("Found thingspro-agent for " + i[1] + " (" + i[2] + ")")
try:
direct_method = CloudToDeviceMethod(method_name=method_name, payload=json.loads(payload))
response = registry_manager.invoke_device_module_method(device_id=i[1], module_id=module_id, direct_method_request=direct_method)
#print(response.payload)
if str(i[1]) == str(response.payload['data']['hostName']):
print(str(i[2]), str(i[0]), str(i[1]), response.payload['data']['description'], response.payload['data']['firmwareVersion'], sep=";")
else:
print(str(i[2]), str(i[0]), str(i[1]), response.payload['data']['description'], response.payload['data']['hostName'], response.payload['data']['firmwareVersion'], sep=";")
except:
print(str(i[2]), str(i[0]), str(i[1]), "UNREACHABLE",sep=";")
else:
print("No thingspro-agent available for " + i[1] + " (" + i[2] + ")")

View File

@@ -1,144 +1,144 @@
import datetime
import time
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import jq
import json
# Function to authenticate and get token
def authenticate(device_ip, payload):
auth_url = f"https://{device_ip}:8443/api/v1/auth"
response = requests.post(auth_url, json=payload, verify=False)
if response.status_code == 200:
token = response.json()["data"]["token"]
#print(f"Authentication successful. Token received: {token}")
print(" authenticated!")
return token
else:
print(f"Authentication failed. Status code: {response.status_code}")
return None
# Function to send PATCH request
def send_patch_request(device_ip, token, connection_string):
headers = {
"mx-api-token": token
}
payload = {
"provisioning": {
"source": "manual",
"connectionString": connection_string,
"enable": True
}
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"PATCH request successful for device {device_ip}")
else:
print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}")
# Function to send UPGRADE request
def send_upgrade_request(device_ip, token, upgrade_url):
headers = {
"mx-api-token": token
}
payload = {
"deleteFileAfterInstallComplete": True,
"install": True,
"url": upgrade_url
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
response = requests.post(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"POST request successful for device {device_ip}")
else:
print(f"Failed to send POST request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def get_upgrade_jobs(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/7"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
json_data = json.loads(response.content.decode())
json_str = json.dumps(json_data, indent=4)
#print(json_str)
print(jq.compile('.data.tasks[0].progress').input(json.loads(json_str)).first(), end="% speed: ")
print(jq.compile('.data.tasks[0].speed').input(json.loads(json_str)).first())
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def get_API_1(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge/messages"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
parsed = json.loads(response.content.decode())
print(json.dumps(parsed, indent=4))
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
# Read the Excel file
# df = pd.read_excel("")
# df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
payload_auth = {
"acceptEULA": True,
"name": "",
"password": ""
}
if payload_auth["name"] == "" or payload_auth["password"] == "":
print("Provide the credentials before running the script!")
exit(10)
ip_address = "10.197.35.116"
token = authenticate(ip_address, payload_auth)
upgrade_url = ""#"https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml"
if upgrade_url == "":
print("Provide upgrade URL before running the script!")
exit(12)
if token:
while True:
print(datetime.datetime.now().strftime("%H:%M:%S"), end=" ")
get_upgrade_jobs(ip_address, token)
time.sleep(60)
# for index, row in df.iterrows():
# device_name = row['device_name']
# device_ip_address_https = row['device_ip_address_http']
# connection_string = row['connection_string']
# upgrade_url = "https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml"
# # Authenticate and get token
# payload_auth = {
# "acceptEULA": True,
# "name": "",
# "password": ""
# }
# print(device_name, end="")
# token = authenticate(device_ip_address_https, payload_auth)
# if token:
# get_API(device_ip_address_https, token)
# print("\n")
import datetime
import time
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import jq
import json
# Function to authenticate and get token
def authenticate(device_ip, payload):
auth_url = f"https://{device_ip}:8443/api/v1/auth"
response = requests.post(auth_url, json=payload, verify=False)
if response.status_code == 200:
token = response.json()["data"]["token"]
#print(f"Authentication successful. Token received: {token}")
print(" authenticated!")
return token
else:
print(f"Authentication failed. Status code: {response.status_code}")
return None
# Function to send PATCH request
def send_patch_request(device_ip, token, connection_string):
headers = {
"mx-api-token": token
}
payload = {
"provisioning": {
"source": "manual",
"connectionString": connection_string,
"enable": True
}
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"PATCH request successful for device {device_ip}")
else:
print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}")
# Function to send UPGRADE request
def send_upgrade_request(device_ip, token, upgrade_url):
headers = {
"mx-api-token": token
}
payload = {
"deleteFileAfterInstallComplete": True,
"install": True,
"url": upgrade_url
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
response = requests.post(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"POST request successful for device {device_ip}")
else:
print(f"Failed to send POST request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def get_upgrade_jobs(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/7"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
json_data = json.loads(response.content.decode())
json_str = json.dumps(json_data, indent=4)
#print(json_str)
print(jq.compile('.data.tasks[0].progress').input(json.loads(json_str)).first(), end="% speed: ")
print(jq.compile('.data.tasks[0].speed').input(json.loads(json_str)).first())
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def get_API_1(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge/messages"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
parsed = json.loads(response.content.decode())
print(json.dumps(parsed, indent=4))
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
# Read the Excel file
# df = pd.read_excel("")
# df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
payload_auth = {
"acceptEULA": True,
"name": "",
"password": ""
}
if payload_auth["name"] == "" or payload_auth["password"] == "":
print("Provide the credentials before running the script!")
exit(10)
ip_address = "10.197.35.116"
token = authenticate(ip_address, payload_auth)
upgrade_url = ""#"https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml"
if upgrade_url == "":
print("Provide upgrade URL before running the script!")
exit(12)
if token:
while True:
print(datetime.datetime.now().strftime("%H:%M:%S"), end=" ")
get_upgrade_jobs(ip_address, token)
time.sleep(60)
# for index, row in df.iterrows():
# device_name = row['device_name']
# device_ip_address_https = row['device_ip_address_http']
# connection_string = row['connection_string']
# upgrade_url = "https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml"
# # Authenticate and get token
# payload_auth = {
# "acceptEULA": True,
# "name": "",
# "password": ""
# }
# print(device_name, end="")
# token = authenticate(device_ip_address_https, payload_auth)
# if token:
# get_API(device_ip_address_https, token)
# print("\n")

View File

@@ -1,147 +1,302 @@
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import jq
import json
# Function to authenticate and get token
def authenticate(device_ip, payload):
auth_url = f"https://{device_ip}:8443/api/v1/auth"
response = requests.post(auth_url, json=payload, verify=False)
if response.status_code == 200:
token = response.json()["data"]["token"]
#print(f"Authentication successful. Token received: {token}")
print(" authenticated!")
return token
else:
print(f"Authentication failed. Status code: {response.status_code}")
return None
# Function to send PATCH request
def send_patch_request(device_ip, token, connection_string):
headers = {
"mx-api-token": token
}
payload = {
"provisioning": {
"source": "manual",
"connectionString": connection_string,
"enable": True
}
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"PATCH request successful for device {device_ip}")
else:
print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}")
# Function to send UPGRADE request
def send_upgrade_request(device_ip, token, upgrade_url):
headers = {
"mx-api-token": token
}
payload = {
"deleteFileAfterInstallComplete": True,
"install": True,
"url": upgrade_url
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
response = requests.post(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"POST request successful for device {device_ip}")
else:
print(f"Failed to send POST request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def get_upgrade_jobs(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/2"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
json_data = json.loads(response.content.decode())
json_str = json.dumps(json_data)
print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def put_API(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge/reset"
response = requests.put(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
print(response.content.decode())
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
def get_API(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
print(response.content.decode())
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
# Read the Excel file
excel_file_path = ""
if excel_file_path == "":
print("Provide Excel file path before running the script!")
exit(11)
df = pd.read_excel(excel_file_path)
df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
for index, row in df.iterrows():
device_name = row['device_name']
device_ip_address_https = row['device_ip_address_http']
connection_string = row['connection_string']
upgrade_url = "" #https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml
if upgrade_url == "":
print("Provide upgrade URL before running the script!")
exit(12)
# Authenticate and get token
payload_auth = {
"acceptEULA": True,
"name": "",
"password": ""
}
if payload_auth["name"] == "" or payload_auth["password"] == "":
print("Provide the credentials before running the script!")
exit(10)
print(device_name, end="")
token = authenticate(device_ip_address_https, payload_auth)
if token:
get_API(device_ip_address_https, token)
print("\n")
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import jq
import json
# Function to authenticate and get token
def authenticate(device_ip, payload):
auth_url = f"https://{device_ip}:8443/api/v1/auth"
response = requests.post(auth_url, json=payload, verify=False)
if response.status_code == 200:
token = response.json()["data"]["token"]
#print(f"Authentication successful. Token received: {token}")
#print(" authenticated!")
return token
else:
print(f"Authentication failed. Status code: {response.status_code}")
return None
# Function to send PATCH request
def send_patch_request(device_ip, token, connection_string):
headers = {
"mx-api-token": token
}
payload = {
"provisioning": {
"source": "manual",
"connectionString": connection_string,
"enable": True
}
}
patch_url = f"https://{device_ip}:8443/api/v1/azure-iotedge"
response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
print(f"PATCH request successful for device {device_ip}")
else:
print(f"Failed to send PATCH request to device {device_ip}. Status code: {response.status_code}")
# Function to send PATCH request
def patch_time(device_ip, token):
headers = {
"mx-api-token": token
}
# payload = {
# "ntp": {
# "source": "timeserver",
# "server": "10.84.171.254",
# "enable": True
# }
# }
payload = {
"timezone": "America/Chicago"
}
patch_url = f"https://{device_ip}:8443/api/v1/device/time"
response = requests.patch(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
json_data = json.loads(response.content.decode())
time = json_data['data']['time']
timezone = json_data['data']['timezone']
last = json_data['data']['lastUpdateTime']
server = json_data['data']['ntp']['server']
enabled = json_data['data']['ntp']['enable']
print(time + " " + timezone + " " + last + " " + server + " " + str(enabled))
else:
json_data = json.loads(response.content.decode())
#print(json.dumps(json_data, indent=2))
# Function to send UPGRADE request
def send_upgrade_request(device_ip, token, upgrade_url):
headers = {
"mx-api-token": token
}
payload = {
"download": True,
"install": True,
"url": upgrade_url,
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
response = requests.post(patch_url, json=payload, headers=headers, verify=False)
json_data = json.loads(response.content.decode())
id = json_data['data']['id']
return id
# Function to send UPGRADE request
def get_upgrade_job(device_ip, token, id):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#print(json_str)
#print(json_data['data'][json_data['count'] - 1]['parameter']['url'], json_data['data'][json_data['count'] - 1]['state'], json_data['count'])
json_data = json.loads(response.content.decode())
getid = json_data['data']['id']
created = json_data['data']['createdAt']
cur_status = json_data['data']['state']
current_tasks = json_data['data']['completedTask']
total_tasks = json_data['data']['totalTask']
print("JOB #" + str(getid) + " " + str(current_tasks) + "/" + str(total_tasks))
print("CREATED ON: " + str(created))
print("CURRENT STATUS: " + str(cur_status))
print(json.dumps(json_data, indent=2))
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
def get_upgrade_jobs(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#print(json_str)
#print(json_data['data'][json_data['count'] - 1]['parameter']['url'], json_data['data'][json_data['count'] - 1]['state'], json_data['count'])
json_data = json.loads(response.content.decode())
count = json_data['count']
print(str(count))
for i in range(count):
getid = json_data['data'][i]['id']
created = json_data['data'][i]['createdAt']
cur_status = json_data['data'][i]['state']
current_tasks = json_data['data'][i]['completedTask']
total_tasks = json_data['data'][i]['totalTask']
print("JOB #" + str(getid) + " " + str(current_tasks) + "/" + str(total_tasks))
print("CREATED ON: " + str(created))
print("CURRENT STATUS: " + str(cur_status))
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content)
# Function to send UPGRADE request
def start_upgrade_job(device_ip, token, id):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/{id}/start"
response = requests.put(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
json_data = json.loads(response.content.decode())
curid = json_data['data']['id']
startedat = json_data['data']['startedAt']
print("Job #" + str(curid) + " started on " + str(startedat))
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
# Function to send UPGRADE request
def put_API(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/3/start"
response = requests.put(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode())
print(json_data['data']['firmwareVersion'])
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
def get_API(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/device/general"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode())
hostname = json_data['data']['hostName']
serial = json_data['data']['serialNumber']
version = json_data['data']['firmwareVersion']
description = json_data['data']['description']
print(hostname + " " + serial + " " + version + " " + description)
#json_str = json.dumps(json_data, indent=2)
#print(json_str)
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
def get_time(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/device/time"
response = requests.get(patch_url, json=payload, headers=headers, verify=False)
if response.status_code == 200:
#print(f"GET request successful for device {device_ip}")
#json_data = json.loads(response.content.decode())
#json_str = json.dumps(json_data)
#print(jq.compile('.data.completedAt').input(json.loads(json_str)).first())
json_data = json.loads(response.content.decode())
time = json_data['data']['time']
timezone = json_data['data']['timezone']
last = json_data['data']['lastUpdateTime']
print(time + " " + timezone + " " + last)
#json_str = json.dumps(json_data, indent=2)
#print(json_str)
else:
print(f"Failed to send GET request to device {device_ip}. Status code: {response.status_code}")
print(response.content.decode())
def delete_API(device_ip, token):
headers = {
"mx-api-token": token
}
payload = {
}
patch_url = f"https://{device_ip}:8443/api/v1/upgrades/5"
response = requests.delete(patch_url, json=payload, headers=headers, verify=False)
print(response.status_code)
json_data = json.loads(response.content.decode())
json_str = json.dumps(json_data, indent=2)
print(json_str)
# Read the Excel file
# excel_file_path = ""
# if excel_file_path == "":
# print("Provide Excel file path before running the script!")
# exit(11)
# df = pd.read_excel(excel_file_path)
# df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# for index, row in df.iterrows():
# device_name = row['device_name']
# device_ip_address_https = row['device_ip_address_http']
# connection_string = row['connection_string']
# upgrade_url = "" #https://files.thingsprocloud.com/package/moxa-aig-301-series-includes-security-patch-firmware-v1.0.deb.yaml
# if upgrade_url == "":
# print("Provide upgrade URL before running the script!")
# exit(12)
# # Authenticate and get token
# payload_auth = {
# "acceptEULA": True,
# "name": "",
# "password": ""
# }
# if payload_auth["name"] == "" or payload_auth["password"] == "":
# print("Provide the credentials before running the script!")
# exit(10)
# print(device_name, end="")
# token = authenticate(device_ip_address_https, payload_auth)
# if token:
# get_API(device_ip_address_https, token)
# print("\n")
for i in range(193, 222):
upgrade_url = "https://files.thingsprocloud.com/package/Upgrade_AIG-301_2.4.0-4020_IMG_1.4_to_1.5.deb.yaml"
payload_auth = {
"acceptEULA": True,
"name": "admin",
"password": "admin@123"
}
device_ip_address = str("10.84.171." + str(i))
#print(device_ip_address, end="")
token = authenticate(device_ip_address, payload_auth)
if token:
#id = send_upgrade_request(device_ip_address,token,upgrade_url)
#print(id)
#get_upgrade_job(device_ip_address, token, 6)
#start_upgrade_job(device_ip_address, token, id)
#put_API(device_ip_address, token)
#patch_time(device_ip_address,token)
#get_time(device_ip_address, token)
#delete_API(device_ip_address,token)
get_API(device_ip_address, token)
else:
print("Authentication failed!")

View File

@@ -1,104 +1,112 @@
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import jq
import json
import scp
import paramiko
def scp_file(local_path, remote_path, hostname, username, password):
try:
# Create a new SSH client
ssh_client = paramiko.SSHClient()
# Automatically add the server's host key
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the server
ssh_client.connect(hostname, username=username, password=password)
# Use SCP to transfer the file
with scp.SCPClient(ssh_client.get_transport()) as scp_client:
scp_client.put(local_path, remote_path)
print("File transferred successfully")
except Exception as e:
print(f"Error: {e}")
finally:
# Close the SSH connection
ssh_client.close()
def ssh_execute_command_with_password(hostname, username, password, command):
try:
# Create a new SSH client
ssh_client = paramiko.SSHClient()
# Automatically add the server's host key
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the server
ssh_client.connect(hostname, username=username, password=password)
# Execute the command with sudo -S to read password from stdin
stdin, stdout, stderr = ssh_client.exec_command('sudo -k -S ' + command)
stdin.write(password + '\n')
stdin.flush()
# Read the output
output = stdout.read().decode('utf-8')
error = stderr.read().decode('utf-8')
# Print output and errors, if any
if output:
print("Command output:")
print(output)
if error:
print("Command error:")
print(error)
print("Command executed successfully")
except Exception as e:
print(f"Error: {e}")
finally:
# Close the SSH connection
ssh_client.close()
# Read the Excel file
excel_file_path = ""
if excel_file_path == "":
print("Provide Excel file path before running the script!")
exit(11)
df = pd.read_excel(excel_file_path)
df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
local_file_path = ""#"./azureiotedge_2.4.0-2697_armhf.mpkg"
if local_file_path == "":
print("Provide upgrade file path before running the script!")
exit(12)
remote_file_path = "./."
username = ""
password = ""
if username == "" or password == "":
print("Provide credentials before running the script!")
exit(10)
command = ""#"appman app install azureiotedge_2.4.0-2697_armhf.mpkg"
if command == "":
print("Provide a command to execute before running the script!")
exit(11)
for index, row in df.iterrows():
device_name = row['device_name']
device_ip_address_https = row['device_ip_address_http']
print(device_name)
ssh_execute_command_with_password(device_ip_address_https, username, password, command)
print("\n")
import pandas as pd
import requests
from urllib3.exceptions import InsecureRequestWarning
import json
import scp
import paramiko
def scp_file(local_path, remote_path, hostname, username, password):
try:
# Create a new SSH client
ssh_client = paramiko.SSHClient()
# Automatically add the server's host key
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the server
ssh_client.connect(hostname, username=username, password=password)
# Use SCP to transfer the file
with scp.SCPClient(ssh_client.get_transport()) as scp_client:
scp_client.put(local_path, remote_path)
print("File transferred successfully")
except Exception as e:
print(f"Error: {e}")
finally:
# Close the SSH connection
ssh_client.close()
def ssh_execute_command_with_password(hostname, username, password, command):
try:
# Create a new SSH client
ssh_client = paramiko.SSHClient()
# Automatically add the server's host key
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the server
ssh_client.connect(hostname, username=username, password=password)
# Execute the command with sudo -S to read password from stdin
stdin, stdout, stderr = ssh_client.exec_command('sudo -k -S ' + command)
stdin.write(password + '\n')
stdin.flush()
# Read the output
output = stdout.read().decode('utf-8')
error = stderr.read().decode('utf-8')
# Print output and errors, if any
if output:
print("Command output:")
print(output)
if error:
print("Command error:")
print(error)
print("Command executed successfully")
except Exception as e:
print(f"Error: {e}")
finally:
# Close the SSH connection
ssh_client.close()
# Read the Excel file
# excel_file_path = ""
# if excel_file_path == "":
# print("Provide Excel file path before running the script!")
# exit(11)
# df = pd.read_excel(excel_file_path)
# df = df[df["device_name"].notnull()]
# Iterate over each row in the DataFrame
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
local_file_path = "AIG-301_1.5.2-20240625_saft1_armhf.deb"
if local_file_path == "":
print("Provide upgrade file path before running the script!")
exit(12)
remote_file_path = "./."
username = "moxa"
password = "moxa"
if username == "" or password == "":
print("Provide credentials before running the script!")
exit(10)
command = ""#"appman app install azureiotedge_2.4.0-2697_armhf.mpkg"
if command == "dpkg -i AIG-301_1.5.2-20240625_saft1_armhf.deb":
print("Provide a command to execute before running the script!")
exit(11)
# for index, row in df.iterrows():
# device_name = row['device_name']
# device_ip_address_https = row['device_ip_address_http']
# print(device_name)
# #ssh_execute_command_with_password(device_ip_address_https, username, password, command)
# print("\n")
for i in range(131, 160):
device_ip_address = str("10.84.157." + str(i))
print(device_ip_address, end="")
if i == 136 or i == 138 or i == 151:
print(" DONE")
else:
print(" TODO")
scp_file(local_file_path, remote_file_path, device_ip_address, username, password)

View File

@@ -1,87 +1,87 @@
import paramiko
import pandas as pd
import getpass
import re
import time
import json
def read_excel(filename, column_name):
df = pd.read_excel(filename)
df = df[df["device_name"].notnull()]
global names
global ips
global connections
names = df["device_name"].tolist()
ips = df["device_ip_address_http"].tolist()
connections = df["connection_string"].tolist()
return ips
def ssh_execute_commands(device_ip, username, password, commands, connection):
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(device_ip, username=username, password=password)
transport = ssh_client.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
session.exec_command("sudo cat /var/thingspro/data/mx-api-token")
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
stdin.write(password + '\n')
stdin.flush()
for line in stdout.read().splitlines():
if not re.search('[Pp]assword', line.decode()):
token = line.decode()
# session = transport.open_session()
# session.set_combine_stderr(True)
# session.get_pty()
# session.exec_command('curl -k -X PUT https://127.0.0.1:8443/api/v1/azure-iotedge/reset -H "Content-Type: application/json" -H "mx-api-token: ' + token + '"')
# stdout = session.makefile('rb', -1)
# for line in stdout.read().splitlines():
# print(line.decode())
print("\n" + connection + "\n")
print(token + "\n")
jq_data = {}
jq_data_2 = {}
jq_data_2["source"] = "manual"
jq_data_2["connectionString"] = connection
jq_data_2["enable"] = True
jq_data["provisioning"] = jq_data_2
json_object = json.dumps(jq_data)
print(json_object + "\n")
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
# -H "Content-Type: application/json" -H "mx-api-token:$(token)'
session.exec_command('curl -k -X PATCH https://127.0.0.1:8443/api/v1/azure-iotedge -H "Content-Type: application/json" -H "mx-api-token: ' + token + '" -d "' + str(json_object) + '"')
stdout = session.makefile('rb', -1)
for line in stdout.read().splitlines():
print(line.decode())
def main():
filename = ""
if filename == "":
print("Provide Excel file path before running the script!")
exit(11)
column_name = "device_ip_address_http"
global names
global ips
global connections
devices = read_excel(filename, column_name)
username = input("Enter SSH username: ")
password = input("Enter SSH password: ")
print(names)
commands = ["sudo bash"] # Add your commands here
for i, device in enumerate(names):
print(f"Connecting to gateway #{i} {device} ({ips[i]})...")
ssh_execute_commands(ips[i], username, password, commands, connections[i])
if __name__ == "__main__":
names = []
ips = []
main()
import paramiko
import pandas as pd
import getpass
import re
import time
import json
def read_excel(filename, column_name):
df = pd.read_excel(filename)
df = df[df["device_name"].notnull()]
global names
global ips
global connections
names = df["device_name"].tolist()
ips = df["device_ip_address_http"].tolist()
connections = df["connection_string"].tolist()
return ips
def ssh_execute_commands(device_ip, username, password, commands, connection):
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(device_ip, username=username, password=password)
transport = ssh_client.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
session.exec_command("sudo cat /var/thingspro/data/mx-api-token")
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
stdin.write(password + '\n')
stdin.flush()
for line in stdout.read().splitlines():
if not re.search('[Pp]assword', line.decode()):
token = line.decode()
# session = transport.open_session()
# session.set_combine_stderr(True)
# session.get_pty()
# session.exec_command('curl -k -X PUT https://127.0.0.1:8443/api/v1/azure-iotedge/reset -H "Content-Type: application/json" -H "mx-api-token: ' + token + '"')
# stdout = session.makefile('rb', -1)
# for line in stdout.read().splitlines():
# print(line.decode())
print("\n" + connection + "\n")
print(token + "\n")
jq_data = {}
jq_data_2 = {}
jq_data_2["source"] = "manual"
jq_data_2["connectionString"] = connection
jq_data_2["enable"] = True
jq_data["provisioning"] = jq_data_2
json_object = json.dumps(jq_data)
print(json_object + "\n")
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
# -H "Content-Type: application/json" -H "mx-api-token:$(token)'
session.exec_command('curl -k -X PATCH https://127.0.0.1:8443/api/v1/azure-iotedge -H "Content-Type: application/json" -H "mx-api-token: ' + token + '" -d "' + str(json_object) + '"')
stdout = session.makefile('rb', -1)
for line in stdout.read().splitlines():
print(line.decode())
def main():
filename = ""
if filename == "":
print("Provide Excel file path before running the script!")
exit(11)
column_name = "device_ip_address_http"
global names
global ips
global connections
devices = read_excel(filename, column_name)
username = input("Enter SSH username: ")
password = input("Enter SSH password: ")
print(names)
commands = ["sudo bash"] # Add your commands here
for i, device in enumerate(names):
print(f"Connecting to gateway #{i} {device} ({ips[i]})...")
ssh_execute_commands(ips[i], username, password, commands, connections[i])
if __name__ == "__main__":
names = []
ips = []
main()

View File

@@ -1,83 +1,83 @@
#!/usr/bin/env python3
import asyncio
import logging
import server_async
import time
import math
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian
from pymodbus.datastore import (
ModbusSequentialDataBlock,
ModbusServerContext,
ModbusSlaveContext,
)
_logger = logging.getLogger(__name__)
async def updating_task(context):
# parameters
fc_as_hex = 3
slave_id = 0x00
address = 0x00
count = 100
# initialization: set values to zero
values = context[slave_id].getValues(fc_as_hex, address, count=count)
values = [0 for v in values]
# infinite loop updating every register to its sine value (period 1 hour, amplitude according to register number)
while True:
await asyncio.sleep(1)
current_time = time.time()
sine_value = sin_wave(current_time)
# BinaryPayloadBuilder is used to convert a float to two Modbus registers
builder = BinaryPayloadBuilder(byteorder=Endian.LITTLE)
for i in range(address, count):
builder.add_32bit_float((i+1) * sine_value)
payload = builder.to_registers()
# once the registers of all the sine waves are created, update the values in the simulator
context[slave_id].setValues(fc_as_hex, address, payload)
# sin wave value calculator
period = 3600
def sin_wave(time_elapsed):
return math.sin(2 * math.pi * time_elapsed / period)
# server start setup function
def setup_updating_server(cmdline=None):
# define the registers
num_floats = 100
float_values = [float(i + 0.5) for i in range(num_floats)]
builder = BinaryPayloadBuilder(byteorder=Endian.LITTLE)
for value in float_values:
builder.add_32bit_float(value)
payload = builder.to_registers()
# create a Modbus simulator with the previously generated registers
datablock = ModbusSequentialDataBlock(0x01, payload)
context = ModbusSlaveContext(di=datablock, co=datablock, hr=datablock, ir=datablock)
context = ModbusServerContext(slaves=context, single=True)
return server_async.setup_server(
description="Run asynchronous server.", context=context, cmdline=cmdline
)
# asynchronous function that will call the values updating function with the arguments (modbus registers layout) of the created server
async def run_updating_server(args):
task = asyncio.create_task(updating_task(args.context))
await server_async.run_async_server(args) # start the server
task.cancel()
# main function that will setup the server, start it and run the function what will update the values of the registers
async def main(cmdline=None):
run_args = setup_updating_server(cmdline=cmdline)
await run_updating_server(run_args)
if __name__ == "__main__":
asyncio.run(main(), debug=True)
#!/usr/bin/env python3
import asyncio
import logging
import server_async
import time
import math
from pymodbus.payload import BinaryPayloadBuilder
from pymodbus.constants import Endian
from pymodbus.datastore import (
ModbusSequentialDataBlock,
ModbusServerContext,
ModbusSlaveContext,
)
_logger = logging.getLogger(__name__)
async def updating_task(context):
# parameters
fc_as_hex = 3
slave_id = 0x00
address = 0x00
count = 100
# initialization: set values to zero
values = context[slave_id].getValues(fc_as_hex, address, count=count)
values = [0 for v in values]
# infinite loop updating every register to its sine value (period 1 hour, amplitude according to register number)
while True:
await asyncio.sleep(1)
current_time = time.time()
sine_value = sin_wave(current_time)
# BinaryPayloadBuilder is used to convert a float to two Modbus registers
builder = BinaryPayloadBuilder(byteorder=Endian.LITTLE)
for i in range(address, count):
builder.add_32bit_float((i+1) * sine_value)
payload = builder.to_registers()
# once the registers of all the sine waves are created, update the values in the simulator
context[slave_id].setValues(fc_as_hex, address, payload)
# sin wave value calculator
period = 3600
def sin_wave(time_elapsed):
return math.sin(2 * math.pi * time_elapsed / period)
# server start setup function
def setup_updating_server(cmdline=None):
# define the registers
num_floats = 100
float_values = [float(i + 0.5) for i in range(num_floats)]
builder = BinaryPayloadBuilder(byteorder=Endian.LITTLE)
for value in float_values:
builder.add_32bit_float(value)
payload = builder.to_registers()
# create a Modbus simulator with the previously generated registers
datablock = ModbusSequentialDataBlock(0x01, payload)
context = ModbusSlaveContext(di=datablock, co=datablock, hr=datablock, ir=datablock)
context = ModbusServerContext(slaves=context, single=True)
return server_async.setup_server(
description="Run asynchronous server.", context=context, cmdline=cmdline
)
# asynchronous function that will call the values updating function with the arguments (modbus registers layout) of the created server
async def run_updating_server(args):
task = asyncio.create_task(updating_task(args.context))
await server_async.run_async_server(args) # start the server
task.cancel()
# main function that will setup the server, start it and run the function what will update the values of the registers
async def main(cmdline=None):
run_args = setup_updating_server(cmdline=cmdline)
await run_updating_server(run_args)
if __name__ == "__main__":
asyncio.run(main(), debug=True)

View File

@@ -1,77 +1,77 @@
import os
import json
import pandas as pd
import pprint
import matplotlib.pyplot as plt
from datetime import datetime
import numpy as np
def process_folder(folder_path, table):
"""
Recursively process each file in the folder and its subfolders.
"""
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
process_file(file_path, table)
def process_file(file_path, table):
"""
Read each line of JSON data from the file and store it in the table.
"""
with open(file_path, 'r') as f:
for line in f:
try:
json_data = json.loads(line)
table.append(json_data)
except json.JSONDecodeError:
print(f"Error decoding JSON in file: {file_path}")
def main(folder_path):
table = []
process_folder(folder_path, table)
# Convert table to pandas DataFrame for easy manipulation
df = pd.DataFrame(table)
index_table = []
enqueued_table = []
emission_table = []
for index, row in df.iterrows():
print(index, end=' ')
index_table.append(index)
print(row['EnqueuedTimeUtc'], end=' ')
enqueued_table.append(row['EnqueuedTimeUtc'])
body_table = []
body_table.append(row['Body'])
body_df = pd.DataFrame(body_table)
for body_index, body_row in body_df.iterrows():
print(body_row['emissionDate'])
emission_table.append(body_row['emissionDate'])
emission_dates = [datetime.strptime(date, '%Y-%m-%dT%H:%M:%SZ') for date in emission_table]
enqueued_dates = [datetime.strptime(date[:19] + date[-1], '%Y-%m-%dT%H:%M:%SZ') for date in enqueued_table]
plt.figure(figsize=(10, 6))
plt.plot(enqueued_dates, index_table, label='Enqueued')
plt.plot(emission_dates, index_table, label='Emission')
plt.xlabel('Time')
plt.ylabel('Index')
plt.title('Index vs Time')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45)
parts = folder_path.split('/')[-4:]
result = '_'.join(parts)
figurename = "index_" + result + ".png"
plt.savefig(figurename, bbox_inches='tight')
if __name__ == "__main__":
folder_path = '/mnt/c/Users/QWPHR/Downloads/JSON_BUFFER_7'
main(folder_path)
import os
import json
import pandas as pd
import pprint
import matplotlib.pyplot as plt
from datetime import datetime
import numpy as np
def process_folder(folder_path, table):
"""
Recursively process each file in the folder and its subfolders.
"""
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
process_file(file_path, table)
def process_file(file_path, table):
"""
Read each line of JSON data from the file and store it in the table.
"""
with open(file_path, 'r') as f:
for line in f:
try:
json_data = json.loads(line)
table.append(json_data)
except json.JSONDecodeError:
print(f"Error decoding JSON in file: {file_path}")
def main(folder_path):
table = []
process_folder(folder_path, table)
# Convert table to pandas DataFrame for easy manipulation
df = pd.DataFrame(table)
index_table = []
enqueued_table = []
emission_table = []
for index, row in df.iterrows():
print(index, end=' ')
index_table.append(index)
print(row['EnqueuedTimeUtc'], end=' ')
enqueued_table.append(row['EnqueuedTimeUtc'])
body_table = []
body_table.append(row['Body'])
body_df = pd.DataFrame(body_table)
for body_index, body_row in body_df.iterrows():
print(body_row['emissionDate'])
emission_table.append(body_row['emissionDate'])
emission_dates = [datetime.strptime(date, '%Y-%m-%dT%H:%M:%SZ') for date in emission_table]
enqueued_dates = [datetime.strptime(date[:19] + date[-1], '%Y-%m-%dT%H:%M:%SZ') for date in enqueued_table]
plt.figure(figsize=(10, 6))
plt.plot(enqueued_dates, index_table, label='Enqueued')
plt.plot(emission_dates, index_table, label='Emission')
plt.xlabel('Time')
plt.ylabel('Index')
plt.title('Index vs Time')
plt.legend()
plt.grid(True)
plt.xticks(rotation=45)
parts = folder_path.split('/')[-4:]
result = '_'.join(parts)
figurename = "index_" + result + ".png"
plt.savefig(figurename, bbox_inches='tight')
if __name__ == "__main__":
folder_path = '/mnt/c/Users/QWPHR/Downloads/JSON_BUFFER_7'
main(folder_path)

View File

@@ -0,0 +1,28 @@
import re
# Function to transform each line
def transform_line(line):
# Use regex to extract parts of the line
match = re.match(r'"([^"]+)","([^"]+)","\[(.*)\]"', line)
if match:
id_part = match.group(1)
date_part = match.group(2)
categories_part = match.group(3)
# Remove extra quotes and split the categories
categories = categories_part.replace('""', '"').split(',')
# Swap categories order and join them with a semicolon
transformed_categories = ','.join(categories[::-1])
# Return the transformed line
return f'"{id_part}",{transformed_categories}'
else:
return None
# Open input file and output file
with open('export_hierarchy', 'r') as infile, open('export_hierarchy_transformed', 'w') as outfile:
for line in infile:
transformed_line = transform_line(line.strip())
if transformed_line:
outfile.write(transformed_line + '\n')

View File

@@ -1,2 +1,2 @@
# ess-moxa-configuration-tools
# ess-moxa-configuration-tools
Repository containing tools, scripts, configurations and command used in the deployment of Moxa AIG-301 devices for I-Sight with Azure IoT Hub.