Jianw
2025-05-14 29f8b36ebb718d2051bf0e7e701973ec4419ee80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
--[[
    编码: WMS-100-03
    名称: PLC-PLCStateChange
    作者:HAN    
    入口函数: PLCStateChange
              
        
    功能说明:
            新兴项目中的线体PLC状态发生变化后会通过这个可编程接口告诉WMS系统
 
            发送过来的数据是一个Json包,格式如下:
            {"device_code":"D001","comm_code":"1001_STUS","value":[1,1,0,1008,0,0,0,100],"time":"2023-09-05 16:16:00"}
            分别表示下面这些状态
            (1) 线体状态   0 空闲 1 运行 2 急停               state
            (2) 光电信号   0 无框 1 有框                      with_tray 有托盘
            (3) 任务号     0~65535                           task_no
            (4) 目标地址   1008  线体编号                     target_addr
            (5) 线体信号   0 无动作 1=允许出框 2=允许进框      signal
            (6) 任务状态反馈 0 无任务 1=出框完成 2=进框完成     task_state
            (7) 外形检测    目前没有用
            (8) 重量       目前没有用
 
    变更记录:
 
--]]
wms_dev = require( "wms_devcomm" )
wms_eq = require( "wms_equipment" )
wms_cntr= require( "wms_container" )
wms_wh = require( "wms_wh" )
 
-- 创建入库作业
-- location 货位 cntr_code 容器编码
-- device_code 输送线线体设备编码
local function create_warehousing_operation( strLuaDEID, device_code, str_loc_code, cntr_code )
    local location
    local nRet
    -- 判断一下是否已经存在托盘号 = cntr_code 的未完成作业,如果已经存在不需要继续创建作业
    -- 因为 PLC 这边有 60s 强制通知策略,因此加一个防护
    nRet, strRetInfo = wms_cntr.InOperation( strLuaDEID, cntr_code )
    if (nRet ~= 0) then lua.Error( strLuaDEID, debug.getinfo(1), "WMS_Container_InOperation失败! " .. strRetInfo) end
    if (strRetInfo == 'yes') then return end
 
    -- 获取货位信息
    nRet, location = wms_wh.Location_GetInfo( strLuaDEID, str_loc_code )
    if ( nRet ~= 0 ) then  lua.Error( strLuaDEID, debug.getinfo(1), 'wms_wh.Location_GetInfo 失败!'..location ) end
    
    -- 创建作业
    local operation = m3.AllocObject(strLuaDEID,"Operation")
    operation.start_wh_code = location.wh_code
    operation.start_area_code = location.area_code
    operation.start_loc_code = location.code
    operation.op_type = wms_base.Get_nConst(strLuaDEID, "作业类型-入库")
    operation.op_def_name = "成品入库"
    operation.cntr_code = cntr_code
    operation.ext_data = device_code      -- 注意:把线体的编码保存在扩展属性中,在生成任务的时候会用到
 
    nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, operation )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【作业】失败!'..strRetInfo ) end        
end
 
-- 创建设备动作队列
-- device_code -- 输送线设备号 task_code -- 任务号 action_code -- 动作码 action -- 动作 line_seg_code -- 线体段号
local function Create_MQAction( strLuaDEID, device_code, task_code, action_code, action, line_seg_code )
    if  ( device_code == nil or device_code == '' ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【设备动作队列】失败! 设备号必须有值' ) end        
    -- step2 获取车辆基本信息
    local eq 
    nRet, eq = wms_eq.Equipment_GetInfo( strLuaDEID, device_code )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), eq ) end
    -- 如果车辆没定义工厂标识返回错误
    if ( eq.factory == '') then
        strErr = "设备编号='"..strForkliftNo.."' 没定义工厂标识!"
        lua.Error( strLuaDEID, debug.getinfo(1), strErr )
    end
 
    -- step3 判断当前车辆的动作码是否已经在队列中(MQ_EQAction)
    local mq_eq_action = m3.AllocObject(strLuaDEID,"MQ_EQAction")
    mq_eq_action.task_code = task_code
    mq_eq_action.eq_code = device_code
    mq_eq_action.action_code = action_code
    mq_eq_action.action = action
    mq_eq_action.data = line_seg_code
 
    -- 线体这里已经存在设备动作记录就不需要继续进行处理
    local strCondition = "N_ACTION_CODE = "..action_code.." AND S_EQ_CODE = '"..mq_eq_action.eq_code.."' AND ( N_B_STATE = 0 OR N_B_STATE = 1 ) "
    strCondition = strCondition.." AND S_DATA = '"..line_seg_code.."'"
    nRet, strRetInfo = mobox.existThisData( strLuaDEID, "MQ_EQAction", strCondition )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), strRetInfo )  end
    -- 如果该车辆编码的动作已经在队列,返回,不做处理
    if ( strRetInfo == "yes" ) then return end
 
    -- step4 把车辆动作写入队列
    mq_eq_action.factory = eq.factory
    mq_eq_action.eq_type = eq.type
    mq_eq_action.eq_type_name = eq.name
    nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, mq_eq_action )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), strRetInfo ) end
end
 
-- 主函数
-- PLC 状态变化后脚本处理程序
function PLCStateChange ( strLuaDEID ) 
    local nRet, strRetInfo
    local input_datajson = {}
 
    -- step1 获取接口中的Data
    nRet, input_datajson = m3.GetSysDataJson( strLuaDEID )
    if ( nRet ~=0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "PLCStateChange 无法获取数据包!"..input_datajson ) end  
    local device_code = lua.Get_StrAttrValue( input_datajson.device_code )
    local comm_code = lua.Get_StrAttrValue( input_datajson.comm_code )
    local value = input_datajson.value
 
        -- step2: 如果线体无框就返回
    if ( value[wms_base.Get_nConst(strLuaDEID,"输送线-光电信号")] ~= 1 ) then return end
 
    -- step3 检查从PLC传入的数据进行合法性判断
    if ( device_code ~= "S7_Line_01") then
        lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备号 device_code 不正确,目前只是接收 S7_Line_01 设备的信号接入!" )
        return
    end
    if ( comm_code == '' ) then 
        lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备通讯项编码不能为空!" ) 
        return
    end
    if ( value == nil ) then 
        lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备状态值为 nil! "  ) 
        return
    end
    
    lua.Debug( strLuaDEID, debug.getinfo(1), "PLC", input_datajson ) 
 
    -- 获取线体编码 line_seg_code
    -- comm_code 的格式是 1001_XXXX  前面是线体编码
    local seg = {}
    local nCount
    seg = lua.split( comm_code, '_' )
    nCount = #seg
    if ( nCount ~= 2 ) then 
        lua.Warning( strLuaDEID, debug.getinfo(1), "PLC传入的设备通讯项编码格式不正确! "..comm_code  )
        return
    end
    local line_seg_code = seg[1]    -- 线体编码
 
    -- step4: 通过OIDeviceCommS请求获取设备目前的托盘号 cntr_code
    local cntr_code = wms_dev.ReadS7PLCCommsData( strLuaDEID, device_code, line_seg_code.."_CNTR" )
 
    lua.Debug( strLuaDEID, debug.getinfo(1), "cntr_code", cntr_code ) 
 
    if  ( type(cntr_code) ~= "string" ) then 
        lua.Error( strLuaDEID, debug.getinfo(1), "调用OIDeviceCommS接口ReadData返回的容器编码格式不对,必须是字符串类型!" ) 
    end
    
    -- step5: 解析返回的容器号,并且进行容器号合格判断 (容器编码TP1/TP2 开头后面7位数字)
    local strHeader         -- 容器号的前3位字符串
    nRet, strHeader = XX_CheckCNTRCode( cntr_code )
    if ( nRet ~= 0 ) then 
        -- 输出 LED 错误信息 这块代码还需要完善
        -- ???
        lua.Error( strLuaDEID, debug.getinfo(1), strHeader ) 
    end
 
    -- step6: 判断容器是否存在? 不存在创建
    if ( wms_cntr.Exist( strLuaDEID, cntr_code ) == false ) then
        -- 【容器】不存在要先创建【容器】
        local container = m3.AllocObject(strLuaDEID,"Container")
        container.code = cntr_code
        nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, container)
        if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【容器】对象失败!'..strRetInfo ) end
    end
 
    -- step7: 通过信号源所在的线体编号确定是 线体目前是做开始入库还是开始出库,或是开始入库到线体目标位置?
    -- 根据 设备编号 + 通讯项目编码 获取货位号 及 货位的出入口属性
    local dev_comms_ext
    nRet, dev_comms_ext = wms_dev.GetDeviceCommSExtInfo ( device_code, comm_code )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), dev_comms_ext ) end
    local pos_type = lua.Get_StrAttrValue( dev_comms_ext.pos_type )
    local str_loc_code = lua.Get_StrAttrValue( dev_comms_ext.loc_code )
    if ( pos_type == nil or pos_type == '' ) then 
        lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的设置不完整,需要设置该通讯项对应线体处所位置的出入口类型!") 
    end
    if ( str_loc_code == nil or str_loc_code == '' ) then 
        lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的设置不完整,需要设置该通讯项对应线体所处的货位编码!") 
    end
 
    -- step8: 光电有框处理,根据线体所属的出入口类型确定作业类型(入库还是出库)
    if ( pos_type == '入库线入口' ) then
        -- 创建入库作业
        create_warehousing_operation( strLuaDEID, device_code, str_loc_code, cntr_code )
    elseif ( pos_type == '出库线入口' ) then
        -- 创建出库作业(暂时不需要)
    elseif ( pos_type == '出库线出口' ) then
        -- 创建出库作业(暂时不需要)        
        -- 根据托盘号获取任务编号 (完整的任务号无法保存到设备里)
        local task = XX_GetTaskByCNTR( strLuaDEID, device_code, cntr_code )
        if ( task ~= nil ) then
            -- 设置动作码和动作名称
            local action_code = wms_base.Get_nConst(strLuaDEID , "输送线-出库口到货")   -- 11 
            local action = "输送线-出库口到货"
            -- 把线体编码 line_seg_code 作为data保存到 设备队列
            Create_MQAction( strLuaDEID, device_code, task.code, action_code, action, line_seg_code )
        else
            lua.Error( strLuaDEID, debug.getinfo(1), "无法获取任务号! device_code = "..device_code.." cntr_code = "..cntr_code )
        end        
    elseif ( pos_type == '入库线出口' ) then
        -- 新增设备动作队列
        -- 根据托盘号获取任务编号 (完整的任务号无法保存到设备里)
        local task = XX_GetTaskByCNTR( strLuaDEID, device_code, cntr_code )
        if ( task ~= nil ) then
            -- 设置动作码和动作名称
            local action_code = wms_base.Get_nConst(strLuaDEID , "输送线-入库口到货")   -- 10 
            local action = "输送线-入库口到货"
            -- 把线体编码 line_seg_code 作为data保存到 设备队列
            Create_MQAction( strLuaDEID, device_code, task.code, action_code, action, line_seg_code )
        else
            lua.Error( strLuaDEID, debug.getinfo(1), "无法获取任务号! device_code = "..device_code.." cntr_code = "..cntr_code )
        end
 
    else
        lua.Error( strLuaDEID, debug.getinfo(1), "设备通讯项'"..comm_code.."'的出入口类型设置不正确!") 
    end
 
end