Код для контроллера Siemens Logo S300. Читает счетчик контроллера, обнуляет его, на основании данных формирует xls файл и отправляет его по почте всем причастным. Код на Python 3:
import xlwt
import snap7
import struct
import os
import smtplib
from snap7 import snap7types
from ctypes import c_int, byref, c_uint16, c_int32
from datetime import timedelta, datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
#from email.utils import formatdate
from email import encoders
##################################################################
# Developed in memory about Sheykin I. P. #
##################################################################
'''
# Для полноценной реализации массовой рассылки писем - необходимо через
# корпоративный портал заказать создание группы рассылки с именем
# _tam22-uboy, например. В этом случае, адресная книга скрипта сократится до одного
# через helpdesk запрашивают добавление своих учетных записей в группу рассылки
# _tam22-uboy, заявку согласовывает директор завода, и кто-то из вас, как
# владельцев группы. Далее, все по накатанной: скрипт раз в сутки шлет
# отчет на указанную группу. Все кто в группе этот отчет получают. Данный
# вариант развития сокбытий необходим потому, что в отсутствии группы рассылки
# вам в дальнейшем придется вручную добавлять адреса в словарь addressbook.
# А вмешиваться в код скрипта, который работает в продакшене - это всегда риск.
#
#
# Так же, рекомендовал бы через корпоративный портал оформить заявку к сетевому
# файловому каталогу размером в пару гигабайт. А затем складывать именно туда
# все отчеты, которые данный скрипт формирует. Это потребует не значительной
# модернизации текущего кода.
'''
# Формирование листа почтовой рассылки
# Лепешкин Евгегений
# Кирьянов Олег
# Левковский Алексей
addressbook = [
'e.lepeshkin@cherkizovo.com'
#'o.kiryianov@cherkizovo.com',
#'a.levkovskiy@cherkizovo.com'
]
# Получаем данные счетчика PLC
IP = "172.22.232.249"
RACK = 0
SLOT = 2
START_ADDRESS = 1
SIZE = 1
AREA = snap7types.S7AreaDB
WORDLEN = snap7types.S7WLDWord
TYPE_ = snap7.snap7types.wordlen_to_ctypes[WORDLEN]
DATA = (TYPE_ * SIZE)()
VALUE_W = 0
AMOUNT_W = 1
DATA_W = bytearray(struct.pack(">l", VALUE_W))
CDATA_W = (TYPE_ * AMOUNT_W).from_buffer_copy(DATA_W)
plc = snap7.client.Client()
plc.connect(IP, RACK, SLOT)
if plc.get_connected():
plc.library.Cli_ReadArea(plc.pointer, AREA, 0, START_ADDRESS, SIZE,
WORDLEN, byref(DATA))
result = struct.unpack_from(">l", DATA)[0]
# Пробуем обнулить счетчик
plc.library.Cli_WriteArea(plc.pointer, AREA, 0, START_ADDRESS,
AMOUNT_W, WORDLEN, byref(CDATA_W))
plc.destroy()
# Формируем и сохраняем XLS файл
Y = datetime.now().strftime("%Y")
check_year = os.path.exists(Y)
if check_year == False:
try:
os.mkdir(Y)
except PermissionError:
os.abort()
now = datetime.now().strftime("%d_%m_%Y_%H-%M-%S_[%A]")
check_folder = os.path.exists(Y + '/' + now)
if check_folder == False:
try:
os.mkdir(Y + '/' + now)
except PermissionError:
os.abort()
file_name = now + ".xls"
sheet_name = "Лист 1"
check_file = os.path.exists(Y + '/' + now + '/' + file_name)
if check_file == False:
try:
header = [f'Дата', f'Время выгрузки отчета', f'Количество тушек', f'Состояние счетчика']
datatype = [datetime.now().strftime("%d.%m.%Y"),
datetime.now().strftime("%H:%M:%S"), result, 'Обнулен']
workbook = xlwt.Workbook()
sheet = workbook.add_sheet(sheet_name)
for column, heading in enumerate(header):
sheet.write(1, column, heading, xlwt.easyxf("pattern: pattern solid,\
fore_colour light_green; font: bold on; align: horiz center; borders: top_color black,\
bottom_color black, right_color black, left_color black,\
left thin, right thin, top thin, bottom thin;"))
sheet.col(0).width = 5000
sheet.col(1).width = 8000
sheet.col(2).width = 5000
sheet.col(3).width = 8000
for column, heading in enumerate(datatype):
sheet.write(2, column, heading, xlwt.easyxf("align: horiz center; borders: top_color black,\
bottom_color black, right_color black, left_color black, left thin,\
right thin, top thin, bottom thin;"))
workbook.save(Y + '/' + now + '/' + file_name)
except PermissionError:
os.abort()
# Формируем и отправляем письмо
path_to_file = Y + '/' + now + '/' + file_name
msg = MIMEMultipart()
msg['From'] = "report@cherkizovo.com"
#msg['To'] = ", ".join(addressbook) # для массовой рассылки с исключением цикла
msg['Subject'] = "Отчет по убою"
msg.attach(MIMEText(
"""Добрый день. Во вложении отчет по общему количеству прошедших по конвейеру тушек птицы за смену """ + datetime.now().strftime("%d.%m.%Y") +
"""
\r\nВнимание! Это письмо сформировано автоматически и не требует ответа!"""
))
part = MIMEBase('application', "octet-stream")
part.set_payload(open(path_to_file, "rb").read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="' + file_name)
msg.attach(part)
server = smtplib.SMTP('mow03-mx.cherkizovsky.net')
# Цикл, целью которого является рассылка писем персонально каждому участнику
# рассылки, таким образом, что бы участники рассылки не знали кому еще данное
# письмо отправлено.
try:
for msg['To'] in addressbook:
# msg['To'].split(',') для рассылки с исключением цикла
server.sendmail(msg['From'], msg['To'], msg.as_string())
del msg['To']
server.quit()
print("Successfully sent email")
except SMTPException:
print ("Error: unable to send email")
#
# Developed by E. N. Lepeshkin