时序图
类图
plc db点监听
public void readDB(List<DBInfo> dbInfoList) {
for (DBInfo dbInfo : dbInfoList) {
ThreadUtil.execute(() -> readDB(dbInfo));
}
}
public void readDB(DBInfo dbInfo) {
while (true) {
SiemensS7Net connect = new SiemensS7Net(dbInfo.getSiemensPLCS(),
dbInfo.getIpAddress());
connect.ConnectServer();
String partId = connect.ReadString(dbInfo.getPartIdAddress()).Content;
if (StrUtil.isNotBlank(partId) && !existsInDB(partId)) {
Boolean result = connect.ReadBool(dbInfo.getResultAddress()).Content;
PartRecord record = new PartRecord();
record.setPartId(partId);
record.setResult(result);
record.setTimestamp(new Date());
record.save();
}
}
}
create table Attribute
(
Id uniqueidentifier not null
constraint Attribute_pk
primary key nonclustered,
Name nvarchar(50),
LowerLimit money,
UpperLimit money,
ServiceFK uniqueidentifier
)
create table ProductionRecord
(
Id uniqueidentifier not null
constraint ProductionRecord_pk
primary key nonclustered,
PartId nvarchar(50),
OKPart bit,
Timestamp datetime,
StationFK uniqueidentifier,
MaterialFK uniqueidentifier
)
create table MeasureValue
(
Id uniqueidentifier not null
constraint MeasureValue_pk
primary key nonclustered,
Timestamp datetime,
Value money,
ProductionRecordFK uniqueidentifier
constraint MeasureValue_ProductionRecord_Id_fk
references ProductionRecord
on delete cascade,
AttributeFK uniqueidentifier
constraint MeasureValue_Attribute_Id_fk
references Attribute
on delete cascade
)
drop table if exists #A0
select lead(Timestamp) over (order by Timestamp) nextTimestamp,
Timestamp,
MaterialFK,
lead(MaterialFK) over (order by Timestamp) nextMaterialFk
into #A0
from ProductionRecord;
select Timestamp,
case
when datediff(minute, Timestamp, nextTimestamp) > 4 * 60
then 28
when MaterialFK != nextMaterialFk
then 60
else 999 end downtimeCode
from #A0
where datediff(minute, Timestamp, nextTimestamp) >= 6
public BoxPlot boxPlot(List<Double> valueList) {
Collections.sort(valueList);
int q1Index = NumberUtil.div(valueList.size(), 4, 0).intValue();
int halfIndex = q1Index * 2;
int q3Index = q1Index * 3;
Double q1 = valueList.get(q1Index);
Double median = valueList.get(halfIndex);
Double q3 = valueList.get(q3Index);
Double lowerLimit = q1 - (q3 - q1) * 1.5;
Double upperLimit = q3 + (q3 - q1) * 1.5;
return BoxPlot.builder().q1(q1).median(median)
.q3(q3).lowerLimit(lowerLimit)
.upperLimit(upperLimit).build();
}
select avg(Value) + 3 * stdev(Value) upperLimit,
avg(Value) - 3 * stdev(Value) lowerLimit
from MeasureValue
where Timestamp between @starTime and @endTime
public List<Pareto> pareto(List<Double> valueList) {
Collections.sort(valueList);
Double total = valueList.stream()
.mapToDouble(Double::doubleValue).sum();
List<Pareto> result = new ArrayList<>();
for (Double value : valueList) {
Pareto pareto = Pareto.builder().value(value)
.percent(NumberUtil.div(value, total, 4)).build();
result.add(pareto);
}
return result;
}
( o k + n o k ) ∗ c y c l e t i m e T i m e n a t u r a l − T i m e d o w n t i m e \frac{(ok+nok)*cycle time}{Time_{natural}-Time_{downtime}} Timenatural−Timedowntime(ok+nok)∗cycletime
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 初始化动态数据库源
*
* @param defaultSource 默认数据库
* @param target 默认数据库集
*/
public DynamicDataSource(DataSource defaultSource, Map<Object, Object> target) {
super.setDefaultTargetDataSource(defaultSource);
super.setTargetDataSources(target);
super.afterPropertiesSet();
}
/**
* 设置当前数据库
*
* @param dataSource 当前数据库名
*/
public static void setDataSource(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return CONTEXT_HOLDER.get();
}
}
@Bean
@Primary
public DynamicDataSource dataSource() {
return new DynamicDataSource(defaultSource, targetSource);
}
@Aspect
@Component
public class MultipleDataSourceAspectj {
@Around(value = "@annotation(annotation)")
public Object around(ProceedingJoinPoint point, MultipleDataSource annotation) {
MethodSignature methodSignature = (MethodSignature) point.getSignature();
String[] parameterNames = methodSignature.getParameterNames();
Object[] args = point.getArgs();
//遍历寻找目标数据库并且切换
for (int i = 0; i < parameterNames.length; i++) {
if (parameterNames[i].equals(annotation.stringPropName())) {
DynamicDataSource.setDataSource(args[i].toString());
break;
}
}
return null;
}
}
@MultipleDataSource(stringPropName = "lineId")
DownTimeDto getLastProductTime(Integer lineId);