[PYTHON] I wrote an automatic kitting script for OpenBlocks IoT

We have decided to kit a large number of ultra-small servers ** OpenBlocks ** for IoT gateways. bx1.jpg The OpenBlocks IoT family has Web UI, a dedicated GUI application provided by Plat'Home, installed. image.png According to FAQ of Platt Home, items that can be set from the Web UI such as network settings can be set from the Web UI. It is supposed to be set, and it seems that it should not be set with CUI (Linux command). If you include the scp transfer and execution of the application program, it will take 15 minutes per device. I decided to write a kitting script in Python because it is possible to reduce the total man-hours by creating an automation program from the beginning rather than repeating troublesome GUI operations dozens of times. It sounds good to say that it reduces man-hours, but in reality, I really didn't want to do simple work.

Automating web UI operations

Automated browser operations with Selenium. It's a simple web application, so you're not doing anything special just by making a GET request, typing in a text box, or clicking the save button.

Python


"""
OpenBlocks IoT BX1 Kitting Script stage1
"""
__author__  = "MindWood"
__version__ = "1.00"
__date__    = "13 Mar 2020"

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
import sys

admin_id   = 'adminUser'
admin_pw   = 'adminPass'
passphrase = 'passPhrase'
id_rsa     = 'ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX== mw'
domain     = 'example.com'

options = webdriver.ChromeOptions()
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(10)

#Connect to the OpenBlocks IoT Web UI
driver.get('http://192.168.254.254:880')

#If there is an consent button first, it is judged as the device to be used for the first time
ar = driver.find_elements_by_id('eula_agree')
if len(ar) == 0:
    #Login screen
    driver.find_element_by_name('name').send_keys(admin_id)
    driver.find_element_by_name('password').send_keys(admin_pw)
    driver.find_element_by_name('_act').click()  #Login
else:
    #Administrator account settings and consent screen
    driver.find_element_by_id('eula_agree').click()  #I agree
    time.sleep(1)
    driver.find_element_by_name('_name').send_keys(admin_id)
    driver.find_element_by_name('_password').send_keys(admin_pw)
    driver.find_element_by_name('_password_confirm').send_keys(admin_pw)
    driver.find_element_by_id('save').click()  #save
time.sleep(1)

#system>>Serial screen
driver.get('http://192.168.254.254:880/system/serial.php')
sq = driver.find_element_by_class_name('sq')  #Get serial number
serial_num = sq.find_element_by_xpath('pre').text.strip()
print('Serial number[' + serial_num + ']')

#service>>Basic screen
driver.get('http://192.168.254.254:880/apps/m2miot/basic.php')
time.sleep(1)
driver.find_element_by_id('enable_bluetooth').click()  #Bluetooth permission
driver.find_element_by_id('save').click()  #save
time.sleep(1)

#service>>Status screen
driver.get('http://192.168.254.254:880/apps/m2miot/status.php')
time.sleep(1)
sq = driver.find_element_by_class_name('sq')
hcconfig = sq.find_element_by_xpath('pre').text
p = hcconfig.find('BD Address: ')
bd_adrs = hcconfig[p+12:p+29].replace(':', '')  #BD address acquisition
print('BD address[' + bd_adrs + ']')

#system>>Filter screen
driver.get('http://192.168.254.254:880/system/ipfilter.php')
time.sleep(1)

this_checkbox = driver.find_element_by_id('filter_hold_true')
if not this_checkbox.is_selected(): this_checkbox.click()  #If not checked, check
driver.find_element_by_id('mode_ssh_true').click()  #SSH enabled
driver.find_element_by_id('save').click()  #save
time.sleep(1)

#system>>SSH related screen
driver.get('http://192.168.254.254:880/system/sshd_config.php')
time.sleep(1)
driver.find_element_by_id('deny_passwd_login').click()  #Password authentication prohibited

elm = driver.find_element_by_id('pubkey')
elm.clear()
elm.send_keys(id_rsa)

driver.find_element_by_id('save').click()  #save
time.sleep(1)

#system>>My page screen
driver.get('http://192.168.254.254:880/system/mypage.php')
time.sleep(1)
driver.find_element_by_id('password').send_keys(admin_pw)
driver.find_element_by_id('save').click()  #save
time.sleep(1)

#network>>Basic screen
driver.get('http://192.168.254.254:880/network/basic.php')
time.sleep(1)

elm = driver.find_element_by_id('domainname')
elm.clear()
elm.send_keys(domain)  #domain

elm = driver.find_element_by_id('wlan0_ssid')
elm.clear()
ssid = serial_num + '_MindWood'
elm.send_keys(ssid)  # SSID

elm = driver.find_element_by_id('wlan0_passphrase')
elm.clear()
elm.send_keys(passphrase)  #Passphrase

driver.find_element_by_id('enable_ppp0').click()  #Use PPP
time.sleep(1)

driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')  #Scroll to the bottom line
time.sleep(1)

#SIM settings for SORACOM data only
driver.find_element_by_id('ppp0_apn').send_keys('soracom.io')  # APN
driver.find_element_by_id('ppp0_user').send_keys('sora')  #User name
driver.find_element_by_id('ppp0_pass').send_keys('sora')  #password
driver.find_element_by_id('ppp0_autotype_false').click()  #Do not connect automatically
driver.find_element_by_id('ppp0_set_reconnect_false').click()  #Do not reconnect regularly
driver.find_element_by_id('save').click()  #save
time.sleep(1)

#system>>Password screen
driver.get('http://192.168.254.254:880/system/passwd.php')
time.sleep(1)
driver.find_element_by_id('password').send_keys(admin_pw)
driver.find_element_by_id('password_confirm').send_keys(admin_pw)
driver.find_element_by_id('save').click()  #save

#maintenance>>Reboot screen
driver.get('http://192.168.254.254:880/maintenance/shutdown.php')
time.sleep(1)
sq = driver.find_element_by_class_name('sq')
sq.find_element_by_xpath('//input[@onclick="pre_reboot()"]').click()  #Reboot
driver.find_element_by_id('reboot_btn').click()  #Run
time.sleep(2)

alert = driver.switch_to.alert
alert.accept()  #Respond OK to alert
sys.exit()

Automate file transfer and ssh command execution

Using paramiko and scp packages, we automated the transfer and execution of the application deployment shell. If you try to do it manually, setting the key is a hassle.

Python


"""
OpenBlocks IoT BX1 Kitting Script stage2
"""
__author__  = "MindWood"
__version__ = "1.00"
__date__    = "13 Mar 2020"

import paramiko
import scp
import time

def exec_cmd(cmd, ssh):
    """Execute command with ssh"""
    print('# ' + cmd)
    stdin, stdout, stderr = ssh.exec_command(cmd)
    for out_line in stdout:
        print(out_line.strip('\n'))
    for err_line in stderr:
        print(err_line.strip('\n'))

with paramiko.SSHClient() as ssh:
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    pkey = paramiko.RSAKey.from_private_key_file('bx1_rsa.key')
    ssh.connect(hostname='192.168.254.254', port=22, username='root', password='adminPass', pkey=pkey)

    exec_cmd('rm -f write_firmware.sh; ls -l', ssh)

    with scp.SCPClient(ssh.get_transport()) as scp:
        scp.put('write_firmware.sh', 'write_firmware.sh')

    time.sleep(1)

    exec_cmd('chmod 755 write_firmware.sh; ./write_firmware.sh', ssh)
    time.sleep(2)

    exec_cmd('reboot', ssh)

If you find this helpful!

Recommended Posts

I wrote an automatic kitting script for OpenBlocks IoT
I wrote an automatic installation script for Arch Linux
I wrote an empty directory automatic creation script in Python
AtCoder writer I wrote a script to aggregate the contests for each writer
I made an alternative module for japandas.DataReader
I wrote unit tests for various languages
I wrote the code for Gibbs sampling
I wrote an IPython Notebook-like Tkinter wrapper [Python]
Obstacle (black) I made an automatic avoidance caterpillar.
I wrote an IPython Notebook-like Gtk wrapper [Python]
I wrote a script to upload a WordPress plugin
I tried to make an air lip detection & automatic response BOT for remote work