当前位置: 首页 > news >正文

智慧水务项目(八)基于Django 5.1 版本PyScada详细安装实战

一、说明

PyScada,一个基于Python和Django框架的开源SCADA(数据采集与监视控制系统)系统,采用HTML5技术打造人机界面(HMI)。它兼容多种工业协议,如Modbus TCP/IP、RTU、ASCII等,并具备系统统计、文件操作、网络服务等多项功能。PyScada对服务器硬件要求不高,可灵活适用于各类工业环境。

SCADA系统的核心功能包括自动数据采集、智能分析、高效存储以及实时推送。这些功能使得它在电力、冶金、石油化工等多个领域发挥着重要作用。作为开源项目,PyScada赋予用户自由定制和修改源代码的权利,从而满足不同的工业需求。

尽管PyScada已相当完善,但仍有一些功能仍在开发中,如BACNet、OPC-UA和MeterBus等。详细的安装指南和项目文档可在其官方网站查阅。在云计算日益普及的今天,SCADA系统正不断演变,以适应新的信息技术和工业需求,特别是在数据处理能力、系统灵活性和可扩展性方面。

二、安装

1、安装说明 

ubuntu版本为24.04.2 LTS,系统干净,如果以前玩过pyscada 需要删除

数据库使用mysql8,redis6 , Gunicorn as WSGI HTTP Server and nginx as HTTP Server.

开发工具用vscode 直接远程连接测试服务器开发,

参考:https://blog.csdn.net/jiangkp/article/details/141328574?spm=1011.2415.3001.5331

2、脚本选择

安装脚本选择,这个在执行install.sh时可以选择,我们选择system而不是docker,未来生产部署可以选择docker

根据脚本内容会调用install_system.sh,由于安装过程中发生了很多问题,所以我们做了一些更改,不过大致是差不多的

3、下载Pyscada源码 

#确认安装了git
sudo apt install git
sudo mkdir -p /home/work
sudo chown  -R t400:t400 /home/work
cd /home/work
sudo git clone https://github.com/pyscada/PyScada.git
cd PyScada

4、打包PyScada

# 打包一般用不上
t400@t400:/home/work/PyScada$ python3 -V
Python 3.12.3# 安装必要的包
sudo apt update
sudo apt upgrade
sudo apt install python3-venvsudo python3 -m venv /home/work/PyScada/.venv# 激活虚拟环境
source /home/work/PyScada/.venv/bin/activate(.venv) t400@t400:/home/work/PyScada$ python -V
Python 3.12.3# 安装打包工具
python -m pip install --upgrade pip setuptools wheel# 打包命令
python setup.py sdist bdist_wheel# 退出虚拟环境
(.venv) t400@t400:/home/work/PyScada$ deactivate
t400@t400:/home/work/PyScada$ 

5、安装mysql和redis 

我们用docker和docker-compose安装mysql8,和redis6.2.7

参考

https://blog.csdn.net/jiangkp/article/details/145995259

6、安装Miniconda

由于服务器自带python版本不一样,比方ubuntu20 就是3.8 ubuntu 22好像还是3.8,ubuntu24 是3.12

所以我们安装了conda,保证python 版本一致

sudo apt update && sudo apt upgrade -y
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
chmod +x Miniconda3-latest-Linux-x86_64.sh
./Miniconda3-latest-Linux-x86_64.sh#安装过程交互
按回车查看许可协议,按 q 退出阅读。
输入 yes 同意协议。
设置安装路径(默认:/home/用户名/miniconda3,直接回车使用默认路径)。
提示是否初始化时,输入 yes(这会自动将conda添加到环境变量)#激活与验证
source ~/.bashrc
conda --version  # 应显示版本号(如 `conda 24.5.0`)
conda list       # 查看已安装的包
# 配置国内源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --set show_channel_urls yes
#安装虚拟环境
conda create -n myenv python=3.12  # 创建名为myenv的环境
conda activate myenv             # 激活环境
conda deactivate                 # 退出环境
conda env list                   # 列出所有环境

 7、install.sh说明

该文件就是选择venv安装还是docker安装,我们选择venv

#!/bin/bash# check if the script is run from script directory
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlinkDIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )SOURCE=$(readlink "$SOURCE")[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )
# 以上从第4行到10行的代码作用就是获取本脚本存储位置的绝对路径,在前面加了这么多代码,
# 可以完美解决别名、链接、source、bash -c 等导致的问题#判断上面得到的路径与当前目录是否一致,要保持一致
if [[ "$DIR" != "$PWD" ]]; thenecho "You must run this script from $DIR"exit 1
fi# Make sure only root can run our script
# 确保root运行
if [[ $EUID -ne 0 ]]; thenecho "This script must be run as root" 1>&2exit 1
fi# Choose the config method (venv or docker)
# 下面所有代码就完成一个任务,输入1 就是调用 install_venv.sh
# 输入2 调用install_docker.sh
answer_config=""
echo "choose your installation"while [[ "$answer_config" == "" ]]; doread -p "1: venv, 2: docker : " answer_configcase $answer_config in"1")#remove logs file if exist (to avoid appending)if [ -f logs_install.txt ]; thenrm logs_install.txtfi#execute the install_venv.sh script and output error in logs filesource install_venv.sh 2>&1 | tee -a logs_install.txt 1>&2 | { while IFS= read -r line; do echo "$line"; done; };;"2")#remove logs file if exist (to avoid appending)if [ -f logs_docker.txt ]; thenrm logs_docker.txtfisource install_docker.sh 2>&1 | tee -a logs_docker.txt 1>&2  | { while IFS= read -r line; do echo "$line"; done; };;*)echo "choose a valid configuration"answer_config="";;esac#statements
done

8、install_venv.sh说明以及修改

该文档包括了不少东西,我们在下面源码中注释

说明:

1、数据库我们不用mariadb,而是用mysql8 已经安装

2、redis6也已经安装

3、一些配置常量,有交互输入变为直接写死,主要是为了调试方便,也是为了保证输入的一致性

4、python 版本是3.12,保证conda activate myenv激活myenv

5、django 版本为5.1,老版本的Pyscada是4.2

#!/bin/bash# todo : add inputs for django admin name, password# check if the script is run from script directory
SOURCE=${BASH_SOURCE[0]}
while [ -L "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlinkDIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )SOURCE=$(readlink "$SOURCE")[[ $SOURCE != /* ]] && SOURCE=$DIR/$SOURCE # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR=$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )if [[ "$DIR" != "$PWD" ]]; thenecho "You must run this script from $DIR"exit 1
fi# Make sure only root can run our script
if [[ $EUID -ne 0 ]]; thenecho "This script must be run as root"exit 1
fi#安装部署路径,服务器部署后台项目就在这里
INSTALL_ROOT=/var/www/pyscada
# log存放位置
log_file_dir="/var/log/pyscada/"
# 后面会建立一个django服务项目,放在这里,服务项目的名字也为PyScadaServer 
SERVER_ROOT=$INSTALL_ROOT/PyScadaServer
# pyscada 存放文件的目录,包括虚拟环境
pyscada_home=/home/pyscada
# 安装虚拟环境路径
pyscada_venv=$pyscada_home/.venv# VAR 变量,以前是交互,现在直接在这里修改,因为容易输错,所以写死# ubuntu设置时区 
#  sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime# 时间是否正确,主要是时区,如果设置为n,会退出,所以这里必须是y,所以必须先检查系统时间是否正常
answer_date="y" 
# 代理配置,我们没有用这个          
answer_proxy="n"  
# 没有用到,这个已经在install.sh里选了         
# answer_config=""        
# 数据库的名字,默认是PyScada_db
answer_db_name="PyScada_db"   # 数据库用户,会创建,默认PyScada-user,不是root,用户自己建立,并分配权限    
answer_db_user="PyScada-user"  
#数据库密码,用户设置的对应answer_db_user的密码       
answer_db_password="PyScada-user-password"
#是否安装redis和channels,本来原始代码是在这里安装redis,但是因为redis还是要测试的,或者说也有可能会用外部的redis
# 所以我们这里redis的安装在运行这个脚本之前就安装好了,这里只是安装依赖包,注意和settings.py有所关联。
answer_channels="y"
# 是否全新安装还是更新安装
# 如果为n就是全新安装,为y就是更新一下项目
# 全新安装:
# 1、会重新要求输入这里这些常量,由于我们已经写死了,所以这个功能就没有了,我们就在这里改
# 2、会创建数据库,用户名或者密码,但是如果数据库名称没有变化那么改数据库存在,我们是没有删除后再建立数据库的,
#     就是说数据库还是第一次建立的数据库,这样数据库不会丢失,如果你想全部重建,改个数据库名称就行了
# 3、用户名密码是可以重新设置的,设置有效
# 4、我们知道PyScadaServer项目是一个用来部署的项目,如果这些和settings.py相关的配置变化了,PyScadaServer项目
#      是不会更新的,就算重建也不会更新,试过了,所以我们在重建时会全部删除掉PyScadaServer项目源码,然后再重建
# 5、如果需要更改配置文件,比方说配置email服务器,在这个脚本里没有设置项,那么就需要在模板文件
#     /home/work/PyScada/tests/project_template/project_name/settings.py-tpl 里修改,然后再重建PyScadaServer项目
#     这样就要重新运行install.sh
# 6、三遍提醒不要在PyScadaServer项目里修改代码,很危险,所以我们要修改模板,然后用模板重建,模板在./tests/project_template
# 7、数据库和redis必须安装并测试好,要不然安装项目会报错,在运行install.sh是后面会建立数据表,如果redis不用,可以不装
#   但是answer_channels需要配置为n,我们这里是把redis安装与依赖包安装分开,而在settings.py判断是否需要redis,就是根据是否安装了
#   channels来判断的,if util.find_spec('channels') is not None: 这条语句就是来查询channels的信息
answer_update="n" # 为True就是自动安装,False就是手动安装
# 所谓自动安装就是你通过pip install或uninstall安装和卸载了插件,那么你在重新运行项目时,在加载settings.py里的配置时,
# 会通过【importlib.metadata.distributions()函数用于获取当前环境中所有已安装的Python包及其元数据信息】重新判断是否安装
# 哪些插件,具体代码在settings.py里
# 手动安装就是你你通过pip install或uninstall安装和卸载了插件,在settings.py不会自动判断你是否安装了插件,这时候需要你把安装的插件
# 添加在settings.py里,在下面数组里添加,
# INSTALLED_APPS = [
#   .......
#    'pyscada',
#    'pyscada.core',
#    'pyscada.hmi',
#    'pyscada.export',
#   #在这里添加或删除
#]#其实这个就是如果你通过pip install或uninstall安装和卸载了插件,那么你重新运行pyscada ,gunicorn,否则需要自己到settings里去添加
answer_auto_add_apps="True"
# 错误输出到用户名,在settings.py中使用,需要配置邮件服务器才有效
answer_admin_name="jkp258" 
# 错误输出到email     
answer_admin_mail="jkp258@qq.com"     
#这里是创建超级用户名
answer_web_name="superadmin"   
# web interface admin password,这里是超级用户对应的密码    
answer_web_password="123456"   echo -e "\nPyScada python packages will be installed in the virtual environment $pyscada_venv"function debug(){message=$1echo ""echo $message 1>&2echo ""
}# called in questions_setup
# 用正则表达式判断代理是否正确
function regex_proxy(){echo "regex_proxy" 1>&2regex='^(https?|ftp)://[0-9a-zA-Z.-]+:[0-9]+$';while true; do# read -p "Use proxy? [http://proxy:port or n]: " answer_proxyif [[ $answer_proxy == "n" || $answer_proxy =~ $regex ]]; thenbreakelseecho "Choose a valid proxy"fidoneecho "regex_proxy end" 1>&2
}
# pip3 的代理,不用就相当于 pip3
function pip3_proxy(){if [[ "$answer_proxy" == "n" ]]; thenpip3 $*elseecho "pip3 using" $answer_proxy "for" $* > /dev/ttypip3 --proxy=$answer_proxy $*fi
}
# 安装有关
function pip3_proxy_not_rust(){if [[ "$answer_proxy" == "n" ]]; thenCRYPTOGRAPHY_DONT_BUILD_RUST=1 pip3 install cryptography==3.4.6 --no-cache-dirpip3 $*elseecho "pip3 using" $answer_proxy "for" $* > /dev/ttyCRYPTOGRAPHY_DONT_BUILD_RUST=1 pip3 --proxy=$answer_proxy install cryptography==3.4.6 --no-cache-dirpip3 --proxy=$answer_proxy $*fi
}
# 不用代理,就是apt
function apt_proxy(){if [[ "$answer_proxy" == "n" ]]; thenapt-get $*elseecho "apt using" $answer_proxy "for" $* > /dev/ttyexport http_proxy=$answer_proxyapt-get $*unset http_proxyfi
}
# 正则判断email是否合规
# called in questions_clean_inst_setup
function regex_mail(){debug "regex_mail"regex='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';while true; do# read -p "admin mail ? " answer_admin_mailif [[ $answer_admin_mail =~ $regex ]]; thenbreakelseecho "Choose a valid mail"fidonedebug "regex_mail end"
}
# called in questions_clean_inst_setup
function admin_name_setup(){debug "admin_name_setup"while true; do# read -p "admin name ? " answer_admin_nameif [[ "$answer_admin_name" == "" ]]; thenecho "Choose a valid name"elsebreakfidonedebug "admin_name_setup end"
}# called in questions_setup
function questions_clean_install_setup(){debug "questions_clean_install_setup"#数据库名称密码用户名#read -p "DB name ? [PyScada_db]: " answer_db_name#read -p "DB user ? [PyScada-user]: " answer_db_user#read -sp "DB password ? [PyScada-user-password]: " answer_db_password#echo ""#  名称,就是后台管理系统的登录名 answer_admin_name,我们就叫noknow,就是现在忘了是哪里用了#admin_name_setup# email 就是noknow@qq.comregex_mailproject_admins=$(echo "('${answer_admin_name}', '${answer_admin_mail}' )")echo $project_adminsecho $answer_db_name#定义的超级用户,后面有用到#read -p "web interface admin name [pyscada]: " answer_web_name#read -p "web interface admin password [password]: " answer_web_passwordif [[ "$answer_db_name" == "" ]]; thenanswer_db_name="PyScada_db"fiif [[ "$answer_db_user" == "" ]]; thenanswer_db_user="PyScada-user"fiif [[ "$answer_db_password" == "" ]]; thenanswer_db_password="PyScada-user-password"fiif [[ "$answer_web_name" == "" ]]; thenanswer_web_name="pyscada"fiif [[ "$answer_web_password" == "" ]]; thenanswer_web_password="password"fiwhile true; do#read -p "Auto load pyscada plugins installed ? If False, you need to edit the settings.py file manually to load a plugin. [True/False]: " answer_auto_add_appsif [[ "$answer_auto_add_apps" == "True" ]]; thenecho 'You need to restart pyscada and gunicorn after (un)installing any pyscada plugin.'break;elif [[ "$answer_auto_add_apps" == "False" ]]; thenecho 'You need manually add a plugin to the django project settings and restart pyscada and gunicorn after (un)installing any pyscada plugin.'break;elseecho "Please answer True or False."fidonedebug "questions_clean_install_setup end"
}# called in the core of the script
function questions_setup(){debug "questions_setup"# Date verification#时间是否正确,主要是时区echo 'date :'echo $(date)# read -p "Is the date and time correct ? [y/n]: " answer_dateif [[ "$answer_date" != "y" ]]; thenecho "please set the date correctly or enter 'y'"exit 1fi# Proxy setupregex_proxy# Channels and redis#read -p "Install channels and redis to speed up inter pyscada process communications ? [y/n]: " answer_channels# Clean installation or not# 这里是全新安装,就是更新while true; do#read -p "Update only : if 'y' it will not create DB, superuser, copy services, settings and urls... On a fresh install you should answer 'n' ? [y/n]: " answer_updateif [[ "$answer_update" == "y" ]]; thenbreakelif [[ "$answer_update" == "n" ]]; thenbreakelseecho "Please answer y or n."fidoneif [[ "$answer_update" == "n" ]]; thenquestions_clean_install_setupfidebug "questions_setup end"
}# called in the core of the script
# 安装依赖,有系统的,有虚拟环境的
function install_dependences(){debug "install_dependences"apt_proxy install -y python3-pipecho 'Some python3 packages installed:'# Install prerequisites# 这里去掉   mariadb-server,把libhdf5-103去掉DEB_TO_INSTALL="libatlas-base-devlibffi-devlibhdf5-devlibjpeg-devlibmariadb-devlibopenjp2-7nginxpython3-devpython3-mysqldbpython3-pippython3-venvzlib1g-devpkg-config"apt_proxy install -y $DEB_TO_INSTALL# 删除virtual environmentsudo rm -rf $pyscada_venv# Create virtual environmentsudo -u pyscada python3 -m venv $pyscada_venv# activatesource $pyscada_venv/bin/activatePIP_TO_INSTALL="cffiCythondocutilsgunicornlxmlmysqlclientnumpy"pip3_proxy install --upgrade $PIP_TO_INSTALLdebug "install_dependences end"
}# called in pyscada_init
function web_setup(){debug "web_setup"(cd $SERVER_ROOT# 创建了超级用户sudo -u pyscada -E env PATH=${PATH} python3 manage.py shell << EOF
try:from django.contrib.auth import get_user_modelfrom django.db.utils import IntegrityErrorUser = get_user_model()User.objects.create_superuser('$answer_web_name','team@pyscada.org','$answer_web_password')
except IntegrityError:print('User pyscada already exist')
EOF)# 前面已经安装了Nginx,这里做了配置,包括ssl,并且设置开机启动# Nginxcp extras/nginx_sample.conf /etc/nginx/sites-available/pyscada.confln -sf ../sites-available/pyscada.conf /etc/nginx/sites-enabled/rm -f /etc/nginx/sites-enabled/defaultmkdir -p /etc/nginx/ssl# the certificate will be valid for 5 Years,openssl req -x509 -nodes -days 1780 -newkey rsa:2048 -keyout /etc/nginx/ssl/pyscada_server.key -out /etc/nginx/ssl/pyscada_server.crt -subj '/CN=www.mydom.com/O=My Company Name LTD./C=US'systemctl enable nginx.service # enable autostart on bootsystemctl restart nginx#配置了两个服务gunicorn和pyscada两个服务# Gunicorn and PyScada as systemd unitscp extras/service/systemd/{gunicorn.{socket,service},pyscada_daemon.service} /etc/systemd/system# Rename PyScada service filemv /etc/systemd/system/pyscada_daemon.service /etc/systemd/system/pyscada.service# Fix if gunicorn installed in /usr/bin and not /usr/local/bin -> create symbolic linkif [[ $(which gunicorn) != /usr/local/bin/gunicorn ]] && [[ ! -f /usr/local/bin/gunicorn ]] && [[ -f /usr/bin/gunicorn ]]; thenecho "Creating symcolic link to gunicorn" ;ln -s /usr/bin/gunicorn /usr/local/bin/gunicorn;fidebug "web_setup end"
}# called in the core of the script
#安装redis,redis不用装,但是依耐包还是要装的,注释掉apt_proxy -y install redis-server
function install_channel_redis(){debug "install_channel_redis"#apt_proxy -y install redis-serverif grep -R "Raspberry Pi 3"  "/proc/device-tree/model" ; thenecho "Don't install Rust for RPI3"pip3_proxy_not_rust install --upgrade channels channels-redis asgirefelsepip3_proxy install --upgrade cryptography==3.4.6 channels channels-redis asgireffidebug "install_channel_redis end"
}# called in the core of the script
function pyscada_init(){debug "pyscada_init"(cd $SERVER_ROOT# Migration and static files,数据迁移sudo -u pyscada -E env PATH=${PATH} python3 manage.py migrate#收集静态数据,staic目录下sudo -u pyscada -E env PATH=${PATH} python3 manage.py collectstatic --noinput#收集静态数据,staic目录下# Load fixtures with default configuration for chart lin colors and unitssudo -u pyscada -E env PATH=${PATH} python3 manage.py loaddata colorsudo -u pyscada -E env PATH=${PATH} python3 manage.py loaddata units# Initialize the background service system of pyscada,后台服务sudo -u pyscada -E env PATH=${PATH} python3 manage.py pyscada_daemon init)if [[ "$answer_update" == "n" ]]; thenweb_setupfi# enable the services for autostartsystemctl enable gunicornsystemctl restart gunicornsystemctl enable pyscadasystemctl restart pyscadasleep 1systemctl --quiet is-active pyscadaif [ $? != 0 ] ; thenecho "Can't start pyscada systemd service." > /dev/stderrexit 1fiif [[ "$answer_update" == "n" ]]; thenecho "PyScada installed"echo "Connect to http://127.0.0.1 using :"echo "username : $answer_web_name"echo "password : $answer_web_password"elseecho "PyScada updated"fidebug "pyscada_init end"
}# called in the core of the script
# 创建数据库,已经为改数据库创建用户及权限,这里不是安装数据库,我们用docker-compose单独装了
function db_setup(){debug "db_setup"# CREATE DATABASE IF NOT EXISTS testtest CHARACTER SET utf8;# Create DBsudo docker exec -i mysql8 mysql -u root -p123456 << EOFCREATE DATABASE IF NOT EXISTS ${answer_db_name} CHARACTER SET utf8mb4;CREATE USER '${answer_db_user}'@'%' IDENTIFIED BY '${answer_db_password}';GRANT ALL PRIVILEGES ON ${answer_db_name}.* TO '${answer_db_user}'@'%';FLUSH PRIVILEGES;
EOFdebug "db_setup end"
}#called in the core of the script
# 利用模板创建PyScadaServer,部署运行就是靠这个,Pyscada只是他其中的一个,就当是插件
function template_setup(){debug "template_setup"# add db informations to django templaterm -r ./tests/project_template_tmp/cp -r ./tests/project_template ./tests/project_template_tmp/chmod a+w ./tests/project_template_tmp/project_name/settings.py-tplsudo -u pyscada -E env PATH=${PATH} python3 << EOF
import django
from django.conf import settings
from django.template.loader import render_to_stringsettings.configure(TEMPLATES=[{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': ['./'],  # script dir'OPTIONS': {'string_if_invalid': '{{ %s }}'}, # prevents the other template tags to be replaced by ''}]
)django.setup()
from django.template import Template, Context
with open("./tests/project_template_tmp/project_name/settings.py-tpl", "r+") as f:template = Template(f.read())context = Context({"db_name": "${answer_db_name}","db_user": "${answer_db_user}","db_password": "${answer_db_password}","project_root": "${INSTALL_ROOT}","pyscada_home": "${pyscada_home}","log_file_dir": "${log_file_dir}","project_admins": "${project_admins}","auto_add_apps": "${answer_auto_add_apps}","additional_apps": "","additional_settings": "",})f.seek(0)f.write(template.render(context))f.truncate()
EOF# 先删除,不然修改了,也不变啊sudo -u pyscada rm -rf $SERVER_ROOTsudo -u pyscada mkdir -p $SERVER_ROOTsudo -u pyscada -E env PATH=${PATH} django-admin startproject PyScadaServer $SERVER_ROOT --template ./tests/project_template_tmprm -rf ./tests/project_template_tmpdebug "template_setup end"
}# called in the core of the script
# 用户有关的目录创建,给予权限等等
function user_setup(){debug "user_setup"# Create pyscada userecho "Creating system user pyscada..."useradd -r pyscadamkdir -p $pyscada_homechown -R pyscada:pyscada $pyscada_homemkdir -p $INSTALL_ROOTchown -R pyscada:pyscada $INSTALL_ROOTmkdir -p $pyscada_home/measurement_data_dumpschown -R pyscada:pyscada $pyscada_home/measurement_data_dumpsmkdir ${log_file_dir}chown pyscada:pyscada ${log_file_dir}touch ${log_file_dir}pyscada_{daemon,debug}.logchown pyscada:pyscada ${log_file_dir}pyscada_{daemon,debug}.log# Add rights for usb, i2c and serialadduser www-data pyscadaadduser pyscada dialoutdebug "user_setup end"
}# stop pyscada and show some python3 packages installed
function stop_pyscada(){debug "stop_pyscada"echo "Stopping PyScada"systemctl stop pyscada gunicorn gunicorn.socketsleep 1 # Give systemd time to shutdownsystemctl --quiet is-active pyscadaif [ $? == 0 ] ; thenecho "Can't stop pyscada systemd service. Aborting."exit 1fiecho "PyScada stopped"debug "stop_pyscada end"
}# install process: * means depending on the user answer
: <<'END'
- questions_setup- regex_proxy- *questions_clean_install_setup- admin_name_setup- regex_mail
- stop_pyscada
- user_setup
- install_dependences- apt_proxy- pip3_proxy
- pyscada install
- *install_channel_redis- apt_proxy- pip3_proxy_not_rust- pip3_proxy
- *db_setup
- *template_setup
- pyscada_init- *web_setup
ENDquestions_setupstop_pyscadauser_setupinstall_dependences
# 我们在这里安装前面打包的PyScada-0.8.3-py3-none-any.whl
# pip3_proxy install /home/work/PyScada/dist/pyscada-0.8.3-py3-none-any.whl
# Install PyScada
pip3_proxy install --upgrade .if [[ "$answer_channels" == "y" ]]; theninstall_channel_redis
fiif [[ "$answer_update" == "n" ]]; thendb_setuptemplate_setup
fipyscada_init# fix owner in /home/pyscada
chown -R pyscada:pyscada $pyscada_home

 

 9、模板settings.py-tpl修改

DATABASES = {'default': {'ENGINE':   'django.db.backends.mysql','NAME':     '{{ db_name }}','USER':     '{{ db_user }}','PASSWORD': '{{ db_password }}',#修改部分'HOST': '127.0.0.1','PORT': '3306','OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",}}
}# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = "zh-hans"#TIME_ZONE = 'UTC'
TIME_ZONE = "Asia/Shanghai"#添加修改,配置QQ邮件服务器,可以用喔,不过是我的,请改过来
# email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
DEFAULT_FROM_EMAIL = 'jkp258@qq.com'  #设置发件人,改为管理员的邮件
EMAIL_HOST = 'smtp.qq.com'  # QQ邮箱SMTP服务器(邮箱需要开通SMTP服务)
EMAIL_PORT = 587  # QQ邮箱SMTP服务端口
EMAIL_HOST_USER = 'jkp258@qq.com'  #改为改为管理员的邮件
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False
EMAIL_HOST_PASSWORD = '*********************'  # 授权码  不是你的QQ密码,qq邮箱里可以去申请
EMAIL_PREFIX = 'A Message From PyScada'
# for admins and managers
SERVER_EMAIL=DEFAULT_FROM_EMAIL 
EMAIL_SUBJECT_PREFIX=EMAIL_PREFIX
EMAIL_TIMEOUT=5

10、安装流程图

 11、安装

#确定conda activate myen
sudo ./install.sh

运行过程:

错误:

E: Package 'libhdf5-103' has no installation candidate

ERROR: Could not find a version that satisfies the requirement cffi (from versions: none)

ERROR: No matching distribution found for cffi

注释掉这个就可以了'libhdf5-103吧,有libhdf5-dev就行

安装结束:

PyScada installed

Connect to http://127.0.0.1 using :

username : superadmin

password : 123456

12、界面展示

我的服务器是192.168.1.14,初始界面 

 

选择点击Admin进入另一个界面

 

相关文章:

智慧水务项目(八)基于Django 5.1 版本PyScada详细安装实战

一、说明 PyScada&#xff0c;一个基于Python和Django框架的开源SCADA&#xff08;数据采集与监视控制系统&#xff09;系统&#xff0c;采用HTML5技术打造人机界面&#xff08;HMI&#xff09;。它兼容多种工业协议&#xff0c;如Modbus TCP/IP、RTU、ASCII等&#xff0c;并具…...

DeepSeek在消防救援领域的应用解决方案

DeepSeek在消防救援领域的应用解决方案 一、火灾风险动态感知与早期预警 火灾风险动态感知与早期预警是智慧消防的关键环节&#xff0c;DeepSeek通过多模态数据分析&#xff0c;融合烟雾传感器、热成像摄像头和气体浓度检测等数据&#xff0c;能够识别传统阈值法难以捕捉的火…...

VSCode CMake调试CPP程序

文章目录 1 安装C与CMake插件2 配置CMakeLists.txt3 使用CMake编译调试3.1 编译3.2 调试 4 自定义构建调试参考 1 安装C与CMake插件 C插件 CMake插件 2 配置CMakeLists.txt 编写测试程序 #include<iostream>int main(int argc, char const *argv[]) {int a 1, b 2;i…...

AI Agent工程师认证-学习笔记(3)——【多Agent】MetaGPT

学习链接&#xff1a;【多Agent】MetaGPT学习教程 源代码链接&#xff08;觉得很好&#xff0c;star一下&#xff09;&#xff1a;GitHub - 基于MetaGPT的多智能体入门与开发教程 MetaGPT链接&#xff1a;GitHub - MetaGPT 前期准备 1、获取MetaGPT &#xff08;1&#xff…...

Spring AI 结构化输出详解

一、Spring AI 结构化输出的定义与核心概念 Spring AI 提供了一种强大的功能&#xff0c;允许开发者将大型语言模型&#xff08;LLM&#xff09;的输出从字符串转换为结构化格式&#xff0c;如 JSON、XML 或 Java 对象。这种结构化输出能力对于依赖可靠解析输出值的下游应用程…...

AMGCL库使用示例

AMGCL库使用示例 AMGCL是一个用于解决大规模稀疏线性方程组的C库&#xff0c;它实现了代数多重网格(AMG)预处理器和Krylov子空间迭代求解器。下面是一些AMGCL的使用示例。 基本示例&#xff1a;求解稀疏线性系统 #include <iostream> #include <vector> #includ…...

关于 Java 预先编译(AOT)技术的详细说明,涵盖 GraalVM 的配置、Spring Boot 3.x 的集成、使用示例及优缺点对比

以下是关于 Java 预先编译&#xff08;AOT&#xff09;技术的详细说明&#xff0c;涵盖 GraalVM 的配置、Spring Boot 3.x 的集成、使用示例及优缺点对比&#xff1a; 1. 预先编译&#xff08;AOT&#xff09;技术详解 1.1 核心概念 AOT&#xff08;Ahead-of-Time&#xff09…...

Video Encoder:多模态大模型如何看懂视频

写在前面 大型语言模型(LLM)已经掌握了理解文本的超能力,而多模态大模型(MLLM)则更进一步,让 AI 拥有了“看懂”图像的眼睛。但这还不够!真实世界是动态的、流动的,充满了运动、变化和声音。视频,正是承载这一切动态信息的关键媒介。 让 LLM 看懂视频,意味着 AI 需…...

leetcode0622. 设计循环队列-medium

1 题目&#xff1a;设计循环队列 官方标定难度&#xff1a;中 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一…...

专题十四:动态路由——OSPF

一、OSPF简介 开放式最短路径优先OSPF&#xff08;Open Shortest Path First&#xff09;是IETF组织开发的一个基于链路状态的内部网关协议&#xff08;Interior Gateway Protocol&#xff09;&#xff0c;采用DIjkstra算法&#xff0c;协议号是89。用于自治系统&#xff08;A…...

【蓝桥杯】第十六届蓝桥杯 JAVA B组记录

试题 A: 逃离高塔 很简单&#xff0c;签到题&#xff0c;但是需要注意精度&#xff0c;用int会有溢出风险 答案&#xff1a;202 package lanqiao.t1;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWrit…...

一个项目的架构演进

1&#xff0c;单体架构 垂直升级&#xff1a;4核16GB -> 8核64G 水平扩展&#xff1a;一台服务器扩展成多台 存在以下几个问题 1&#xff0c;提升的性能是有限的 2&#xff0c;更新&#xff0c;维护成本非常高&#xff0c;对于系统中要修改或增加的功能&#xff0c;整个发…...

创建虚拟环境无法加载到pycharm当conda环境,只能为python环境

conda create -n myenv python3.8 然后&#xff0c;在pycharm中&#xff0c;点击 ..." 按钮并浏览到您的 Conda 环境路径。通常&#xff0c;Conda 环境路径位于 ~/.conda/envs/<Your Environment Name> 或 ~/miniconda3/envs/<Your Environment Name> 或 ~/an…...

暴雨打造智能化时代源动力

当清晨的智能管家为您调节室温、日间数字员工自动生成会议纪要、深夜AI外教仍在纠正发音……这不是科幻片&#xff0c;2025年的世界正被智能体悄然重塑。这些能听会想的数智化助理&#xff0c;正在医疗会诊、工业质检、金融风控等多个领域创造着价值。 那么&#xff0c;智能体…...

【ROS2】行为树:BehaviorTree

1、简介 与状态机不同,行为树强调执行动作,而不是状态之间的转换。 行为树是可组合的。可以重复使用简单的行为来构建复杂的行为。 在游戏领域,行为树已经比较流行了。主要用于维护游戏角色的各种动作和状态。 ROS2的导航框架Navigation2中引入了行为树来组织机器人的工作流…...

【HTTP】:应用层协议HTTP(1)

1.HTTP协议 虽然我们说,应用层协议是我们程序猿自己定的.但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用.HTTP(超文本传输协议)就是其中之一。 在互联网世界中&#xff0c;HTTP&#xff08;HyperTextTransfer Protocol&#xff0c;超文本…...

Boost Graph Library (BGL) 介绍与使用示例

Boost Graph Library (BGL) 介绍与使用示例 Boost Graph Library (BGL) 是 Boost 库中用于图论计算的模块&#xff0c;提供了处理图数据结构的通用接口和多种图算法实现。 BGL 主要特性 提供多种图表示方式&#xff1a;邻接表、邻接矩阵等包含常用图算法&#xff1a;DFS、BF…...

数据结构--线性表

单链表的基本操作 1.清空单链表 链表仍然存在&#xff0c;但链表中无元素&#xff0c;成为空链表&#xff08;头指针和头链表仍存在&#xff09;算法思路&#xff1a;依次释放所有结点&#xff0c;并将头结点指针设置为空 2.返回表长 3.取值–取单链表中第i个元素 因为存储…...

电商用户购物行为分析:基于K-Means聚类与分类验证的完整流程

随着电商行业的快速发展,用户行为分析成为企业优化营销策略、提升用户体验的重要手段。通过分析用户的购物行为数据,企业可以挖掘出用户群体的消费特征和行为模式,从而制定更加精准的营销策略。本文将详细介绍一个基于Python实现的电商用户购物行为分析系统,涵盖数据预处理…...

《车辆人机工程-汽车驾驶显示装置》实验报告

汽思考题 汽车显示装置有哪些&#xff1f; 汽车显示装置是车辆与驾驶员、乘客交互的重要界面&#xff0c;主要用于信息展示、功能控制和安全辅助。以下是常见的汽车显示装置分类及具体类型&#xff1a; 一、驾驶舱核心显示装置 1. 仪表盘&#xff08;Instrument Cluster&am…...

三维点云投影二维图像的原理及实现

转自个人博客&#xff1a;三维点云投影二维图像的原理及实现 1. 概述 1.1 原理概述 三维点云模型是由深度相机采集深度信息和RGB信息进行生成的&#xff0c;深度相机能直接获取到深度图和二维RGB图像&#xff0c;也就是说利用相机原本的关系就可以把深度信息投影回二维图像&a…...

使用Golang打包jar应用

文章目录 背景Go 的 go:embed 功能介绍与打包 JAR 文件示例1. go:embed 基础介绍基本特性基本语法 2. 嵌入 JAR 文件示例项目结构代码实现 3. 高级用法&#xff1a;嵌入多个文件或目录4. 使用注意事项5. 实际应用场景6. 完整示例&#xff1a;运行嵌入的JAR 背景 想把自己的一个…...

MySQL数据过滤、转换与标准化

数据处理是数据库操作的重要组成部分&#xff0c;尤其是在大量数据中查找、转换和规范化目标信息的过程中。为了确保数据的有效性与一致性&#xff0c;MySQL提供了一系列数据过滤、转换与标准化的功能。 本教程将深入探讨数据过滤和转换的基本方法及应用&#xff0c;内容涵盖数…...

Linux中安装sentinel

拉取镜像 #我默认拉取最新的 sentinel 镜像 docker pull bladex/sentinel-dashboard 创建容器 docker run --name sentinel -d -p 8858:8858 bladex/sentinel-dashboard 检查是否成功 docker ps 浏览器访问 默认账号密码是 sentinel/sentinel 成功了 开放sentinel端口或者关…...

大模型压缩训练(知识蒸馏)

AI的计算结果不是一个数值&#xff0c;而是一个趋势 一、模型压缩简介 1、深度学习&#xff08;Deep Learning&#xff09;因其计算复杂度或参数冗余&#xff0c;在一些场景和设备上限制了相应的模型部署&#xff0c;需要借助模型压缩、优化加速、异构计算等方法突破瓶颈。 …...

Matlab绘制函数方程图形

Matlab绘制函数方程图形&#xff1a; 多项式计算: polyval 函数 Values of Polynomials: polyval ( ) 绘制方程式图形&#xff1a; 代码如下&#xff1a; >> a[9,-5,3,7]; x-2:0.01:5; fpolyval(a,x); plot(x,f,LineWidth,2); xlabel(x); ylabel(f(x))…...

dify windos,linux下载安装部署,提供百度云盘地址

dify下载安装 dify1.0.1 windos安装包百度云盘地址 通过网盘分享的文件&#xff1a;dify-1.0.1.zip 链接: 百度网盘 请输入提取码 提取码: 1234 dify安装包 linux安装包百度云盘地址 通过网盘分享的文件&#xff1a;dify-1.0.1.tar.gz 链接: 百度网盘 请输入提取码 提取码…...

优化方法介绍(一)

优化方法介绍(一) 本博客是一个系列博客,主要是介绍各种优化方法,使用 matlab 实现,包括方法介绍,公式推导和优化过程可视化 1 失败案例介绍 本文在编写最速下降法的时候使用了经典的求解函数框架,并使用了自适应步长(alpha)机制,即加入参数flag,当出现梯度下降的情…...

Centos7.9 升级内核,安装RTX5880驱动

系统镜像下载 https://vault.centos.org/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2009.iso 系统安装步骤省略 开始安装显卡驱动 远程登录查看内核 [root192 ~]# uname -a Linux 192.168.119.166 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64 x8…...

计算轴承|滚动轴承故障频率

一、轴承故障频率概述 在旋转机械故障诊断中&#xff0c;轴承故障频率&#xff08;BPFO、BPFI、BSF、FTF&#xff09;是重要的分析依据。通过计算这些特征频率&#xff0c;可以帮助工程师&#xff1a; 识别轴承故障类型&#xff08;内圈/外圈/滚动体故障&#xff09;制定振动…...

Python 数据分析01 环境搭建教程

Python 数据分析01 环境搭建教程 一、安装 Python 环境 访问 Python 官方网站 Python 官网&#xff0c;选择适合你操作系统的 Python 版本进行下载。下载完成后&#xff0c;运行安装程序。在安装过程中&#xff0c;建议选择“Add Python to PATH”选项&#xff0c;这样可以在…...

程序化广告行业(80/89):近年发展动态与技术标准演进

程序化广告行业&#xff08;80/89&#xff09;&#xff1a;近年发展动态与技术标准演进 大家好&#xff01;在技术领域探索的过程中&#xff0c;我深刻认识到知识分享的力量&#xff0c;它能让我们在学习的道路上加速前行。写这篇博客&#xff0c;就是希望能和大家一起深入剖析…...

Node.js cluster模块详解

Node.js cluster 模块详解 cluster 模块允许你轻松创建共享同一服务器端口的子进程&#xff08;worker&#xff09;&#xff0c;充分利用多核 CPU 的性能。它是 Node.js 实现高并发的重要工具。 核心概念 主进程&#xff08;Master&#xff09;&#xff1a;负责管理工作进程…...

2025年认证杯数学建模C题完整分析论文(共39页)(含模型、可运行代码)

2025年认证杯数学建模竞赛C题完整分析论文 目录 摘要 一、问题重述 二、问题分析 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1解析 4.1.2问题1模型建立 4.1.3问题1求解代码 4.1.4问题1求解结果 4.2问题2 4.2.1问题2解析 4.2.2问题2模型建…...

PostgreSQL 的 COPY 命令

PostgreSQL 的 COPY 命令 PostgreSQL 的 COPY 命令是高效数据导入导出的核心工具&#xff0c;性能远超常规 INSERT 语句。以下是 COPY 命令的深度解析&#xff1a; 一 COPY 命令基础 1.1 基本语法对比 命令类型语法示例执行位置文件访问权限服务器端COPYCOPY table FROM /p…...

MySQL进阶-存储引擎索引

目录 一&#xff1a;存储引擎 MySQL体系结构 存储引擎介绍 存储引擎特点 InnoDB MyISAM Memory 区别及特点 存储引擎选择 索引 索引概述 介绍 演示 特点 索引结构 概述 二叉树 B-Tree BTree Hash 索引分类 索引分类 聚集索引&二级索引 一&#xff1…...

为什么需要Refresh Token?

后端服务性能 一种方案是在服务器端保存 Token 状态&#xff0c;用户每次操作都会自动刷新&#xff08;推迟&#xff09; Token 的过期时间——Session 就是采用这种策略来保持用户登录状态的。然而仍然存在这样一个问题&#xff0c;在前后端分离、单页 App 这些情况下&#x…...

基于3A4000及CentOS的银河麒麟V10离线源码编译安装VLC

碰到过的一个具体问题&#xff1a; 源码安装vlc-3.0.x版本&#xff0c;需要注意的是&#xff0c;不要安装ffmpeg-5及以上的版本&#xff0c;即只支持ffmpeg-4的版本&#xff0c;因此&#xff0c;要安装vlc-3.0版本&#xff0c;一个重要的依赖时就会ffmpeg-4。报错没有revision…...

Windows for Redis 后台服务运行

下载 redis 安装包 地址&#xff1a;https://github.com/tporadowski/redis/releases 解压zip压缩包&#xff0c;执行 redis-server.exe 即可以窗口模式运行&#xff08;窗口关闭则服务关闭&#xff09; 运行窗口可以看到&#xff0c;端口是 6379 我这里使用 nvaicat 客服端测…...

前端工程化-包管理NPM-package.json 和 package-lock.json 详解

package.json 和 package-lock.json 详解 1.package.json 基本概念 package.json 是 Node.js 项目的核心配置文件&#xff0c;它定义了项目的基本信息、依赖项、脚本命令等。 主要字段 基本信息字段 name: 项目名称&#xff08;必填&#xff09; version: 项目版本&#xf…...

如何在 Linux 中彻底终止被 `Ctrl+Z` 挂起的进程?

问题场景 在 Linux 终端操作时&#xff0c;你是否曾遇到过这样的情况&#xff1f; 当运行一个命令&#xff08;如 ping www.baidu.com&#xff09;时&#xff0c;不小心按下了 CtrlZ&#xff0c;屏幕上显示类似以下内容&#xff1a; ^Z [2] 已停止 ping www.b…...

人工智能100问☞第3问:深度学习的核心原理是什么?

目录 一、通俗解释 二、专业解析 三、权威参考 深度学习的核心原理是​​通过构建多层神经网络结构,逐层自动提取并组合数据特征,利用反向传播算法优化参数,从而实现对复杂数据的高层次抽象和精准预测​​。 一、通俗解释 ​​深度学习的核心原理,就像是教计算机像婴儿…...

基于若依和elementui实现文件上传(导入Excel表)

基于若依和elementui实现文件上传&#xff08;导入Excel表&#xff09; 前端部分&#xff1a; 若依封装了Apache的poi功能&#xff0c;实现文件的上传和下载 若依使用的是JS语法&#xff0c;需要改造为JS语法才能使用 若依如何解决跨域的问题&#xff1a; 在前端的配置文件中…...

2025年第十六届蓝桥杯省赛真题解析 Java B组(简单经验分享)

之前一年拿了国二后&#xff0c;基本就没刷过题了&#xff0c;实力掉了好多&#xff0c;这次参赛只是为了学校的加分水水而已&#xff0c;希望能拿个省三吧 >_< 目录 1. 逃离高塔思路代码 2. 消失的蓝宝思路代码 3. 电池分组思路代码 4. 魔法科考试思路代码 5. 爆破思路…...

OpenHarmony人才认证证书

OpenHarmony人才认证体系目前支持初级工程师认证&#xff0c;要求了解OpenHarmony开源项目、生态进展及系统移植等基础知识&#xff0c;熟练掌握OpenHarmony的ArkUI、分布式软总线、分布式硬件、分布式数据管理等基础能力使用&#xff0c;具备基础的开发能力。 考试流程可参考O…...

Docker--利用dockerfile搭建mysql主从集群和redis集群

Docker镜像制作的命令 链接 Docker 镜像制作的注意事项 链接 搭建mysql主从集群 mysql主从同步的原理 MySQL主从同步&#xff08;Replication&#xff09;是一种实现数据冗余和高可用性的技术&#xff0c;通过将主数据库&#xff08;Master&#xff09;的变更操作同步到一个…...

LLaMA-Factory双卡4090微调DeepSeek-R1-Distill-Qwen-14B医学领域

unsloth单卡4090微调DeepSeek-R1-Distill-Qwen-14B医学领域后&#xff0c;跑通一下多卡微调。 1&#xff0c;准备2卡RTX 4090 2&#xff0c;准备数据集 医学领域 pip install -U huggingface_hub export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download --resum…...

使用ZSH美化Windows系统Git Bash

此前&#xff0c;我们讲解了一种借助 Windows Subsystem for Linux&#xff08;WSL&#xff09;让用户在 Windows 操作系统中运用 Linux Shell 命令&#xff0c;进而高效地实现文件访问、编译等开发工作。 Windows系统命令行的最佳实践 | 听到微笑的博客 这种借助 Windows Su…...

如何使用PyCharm自动化测试

如何使用PyCharm自动化测试 1.打开PyCharm右击文件&#xff0c;点击新建项目 按照如图配置&#xff0c;然后点击创建 2.创建好后&#xff0c;点击文件&#xff0c;然后点击设置 按照如图步骤&#xff0c;查看selenium和webdriver-manager是否存在 3.以上都完成后按照如图创…...

56.评论日记

2025年4月12日22:06:08 小米事故下的众生相_哔哩哔哩_bilibili...