diff --git a/src/main/java/com/iflytop/handacid/app/controller/PreFillController.java b/src/main/java/com/iflytop/handacid/app/controller/PreFillController.java new file mode 100644 index 0000000..ae19aa2 --- /dev/null +++ b/src/main/java/com/iflytop/handacid/app/controller/PreFillController.java @@ -0,0 +1,61 @@ +package com.iflytop.handacid.app.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.iflytop.handacid.common.base.BasePageQuery; +import com.iflytop.handacid.common.model.entity.PreFill; +import com.iflytop.handacid.common.model.entity.User; +import com.iflytop.handacid.common.result.PageResult; +import com.iflytop.handacid.common.result.Result; +import com.iflytop.handacid.common.service.FormulationService; +import com.iflytop.handacid.common.service.PreFillService; +import com.iflytop.handacid.common.service.SolutionService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; + +/** + * 预充设定 + */ +@Tag(name = "\uD83D\uDCA6预充设定") +@RestController +@RequestMapping("/api/pre-fill") +@RequiredArgsConstructor +@Slf4j +public class PreFillController { + private final PreFillService preFillService; + + @Operation(summary = "分页查询用预充设定") + @PostMapping("/page") + public PageResult getPage(@RequestBody BasePageQuery query) { + Page page = new Page<>(query.getPageNum(), query.getPageSize()); + return PageResult.success(preFillService.page(page)); + } + + @Operation(summary = "添加预充设定") + @PostMapping("") + public Result add(@Valid @RequestBody PreFill preFill) { + return preFillService.save(preFill) ? Result.success() : Result.failed(); + } + + @Operation(summary = "修改预充设定") + @PutMapping("") + public Result update(@Valid @RequestBody PreFill preFill) { + return preFillService.updateById(preFill) ? Result.success() : Result.failed(); + } + + @Operation(summary = "删除预充设定") + @DeleteMapping("/{ids}") + public Result delete(@Parameter(description = "ID,多个用逗号分隔") @PathVariable String ids) { + boolean success = preFillService.removeBatchByIds( + Arrays.stream(ids.split(",")).map(Long::valueOf).toList() + ); + return success ? Result.success() : Result.failed(); + } + +} diff --git a/src/main/java/com/iflytop/handacid/app/core/listener/BleGamepadEventListener.java b/src/main/java/com/iflytop/handacid/app/core/listener/BleGamepadEventListener.java index 6e17828..b4789fb 100644 --- a/src/main/java/com/iflytop/handacid/app/core/listener/BleGamepadEventListener.java +++ b/src/main/java/com/iflytop/handacid/app/core/listener/BleGamepadEventListener.java @@ -1,6 +1,7 @@ package com.iflytop.handacid.app.core.listener; import com.iflytop.handacid.app.core.state.DeviceState; +import com.iflytop.handacid.app.scheduled.BleGamepadStateScheduledTask; import com.iflytop.handacid.app.service.ChannelCtrlService; import com.iflytop.handacid.common.service.AuditRecordService; import com.iflytop.handacid.hardware.service.AppEventBusService; @@ -24,6 +25,7 @@ public class BleGamepadEventListener { private final AppEventBusService eventBus; private final ChannelCtrlService channelCtrlService; private final DeviceState deviceState; + private final BleGamepadStateScheduledTask bleGamepadStateScheduledTask; @PostConstruct synchronized public void init() { @@ -65,9 +67,12 @@ public class BleGamepadEventListener { } else if (CmdId.event_ble_gamepad_connected.equals(cmdId)) { log.info("蓝牙手柄 连接成功"); deviceState.getRemoteControlState().setConnected(true); + bleGamepadStateScheduledTask.fetchTrayState(); } else if (CmdId.event_ble_gamepad_disconnected.equals(cmdId)) { log.info("蓝牙手柄 连接断开"); deviceState.getRemoteControlState().setConnected(false); + deviceState.getRemoteControlState().setBatteryLevel(-1); + deviceState.getRemoteControlState().setCharging(false); } } diff --git a/src/main/java/com/iflytop/handacid/app/core/state/RemoteControlState.java b/src/main/java/com/iflytop/handacid/app/core/state/RemoteControlState.java index 0b0bd41..40e0eaa 100644 --- a/src/main/java/com/iflytop/handacid/app/core/state/RemoteControlState.java +++ b/src/main/java/com/iflytop/handacid/app/core/state/RemoteControlState.java @@ -19,7 +19,7 @@ public class RemoteControlState { private volatile boolean connected = false; @Schema(description = "当前电量(0-100%)") - private volatile double batteryLevel = 0; + private volatile double batteryLevel = -1; @Schema(description = "是否正在充电") private volatile boolean charging = false; diff --git a/src/main/java/com/iflytop/handacid/app/scheduled/BleGamepadStateScheduledTask.java b/src/main/java/com/iflytop/handacid/app/scheduled/BleGamepadStateScheduledTask.java index 69d67d0..c635e27 100644 --- a/src/main/java/com/iflytop/handacid/app/scheduled/BleGamepadStateScheduledTask.java +++ b/src/main/java/com/iflytop/handacid/app/scheduled/BleGamepadStateScheduledTask.java @@ -21,7 +21,6 @@ public class BleGamepadStateScheduledTask { @Scheduled(fixedRate = 30 * 1000) public void fetchTrayState() { try { - if (!deviceState.isVirtual()) { boolean is_connect = bleGamepadDriver.is_connected(BleGamepadMid.BleGamePad); deviceState.getRemoteControlState().setConnected(is_connect); diff --git a/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java b/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java index e144c38..d10715d 100644 --- a/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java +++ b/src/main/java/com/iflytop/handacid/app/service/ChannelCtrlService.java @@ -14,10 +14,8 @@ import com.iflytop.handacid.app.core.state.DeviceState; import com.iflytop.handacid.common.model.entity.AuditRecord; import com.iflytop.handacid.common.model.entity.Channel; import com.iflytop.handacid.common.model.entity.Formulation; -import com.iflytop.handacid.common.service.AuditRecordService; -import com.iflytop.handacid.common.service.ChannelService; -import com.iflytop.handacid.common.service.FormulationService; -import com.iflytop.handacid.common.service.SystemConfigService; +import com.iflytop.handacid.common.model.entity.PreFill; +import com.iflytop.handacid.common.service.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -41,6 +39,7 @@ public class ChannelCtrlService { private final AuditRecordService auditRecordService; private final SystemConfigService systemConfigService; private final ChannelService channelService; + private final PreFillService preFillService; /** * 开始加液 @@ -68,14 +67,28 @@ public class ChannelCtrlService { if (SolutionAddMode.AUTO.equals(deviceState.getMode())) {//自动模式 while (!deviceState.isSolutionAddStop()) { handleSolutionAdd(channelStateList); - handleCalculateActualDispensedVolume(channelStateList); + for (ChannelState channelState : channelStateList) {//与缓存的位置比较计算加液量 + Formulation formulation = formulationService.lambdaQuery() + .eq(Formulation::getSolutionId, channelState.getSolutionId()) + .eq(Formulation::getConcentration, channelState.getConcentration()) + .eq(Formulation::getVolume, channelState.getTargetVolume()) + .one(); + handleCalculateActualDispensedVolume(channelState, formulation.getVolume(), formulation.getRevolutions()); + } if (!deviceState.isSolutionAddStop()) { Thread.sleep(deviceState.getDelay() * 1000L); } } } else if (SolutionAddMode.CLICK.equals(deviceState.getMode())) {//点动模式 handleSolutionAdd(channelStateList); - handleCalculateActualDispensedVolume(channelStateList); + for (ChannelState channelState : channelStateList) {//与缓存的位置比较计算加液量 + Formulation formulation = formulationService.lambdaQuery() + .eq(Formulation::getSolutionId, channelState.getSolutionId()) + .eq(Formulation::getConcentration, channelState.getConcentration()) + .eq(Formulation::getVolume, channelState.getTargetVolume()) + .one(); + handleCalculateActualDispensedVolume(channelState, formulation.getVolume(), formulation.getRevolutions()); + } } } catch (Exception e) { throw new RuntimeException(e); @@ -124,23 +137,34 @@ public class ChannelCtrlService { return; } try { + List valveOpenDeviceCommandFutureList = new ArrayList<>(); for (ChannelState channelState : channelStateList) { channelState.setStateCode(ChannelStateCode.PRE); + + DeviceCommand valveOpenDeviceCommand = getValveOpenCommandByChannel(channelState.getChannelCode());//打开阀门 + valveOpenDeviceCommandFutureList.add(deviceCommandService.sendCommand(valveOpenDeviceCommand)); } + CommandUtil.wait(valveOpenDeviceCommandFutureList); + List commandFutureList = new ArrayList<>(); for (ChannelState channelState : channelStateList) { - //打开阀门 - DeviceCommand valveOpenDeviceCommand = getValveOpenCommandByChannel(channelState.getChannelCode()); - CommandFuture valveOpenCommandFuture = deviceCommandService.sendCommand(valveOpenDeviceCommand); - CommandUtil.wait(valveOpenCommandFuture); - - DeviceCommand deviceCommand = getPumpForwardRotateCommandByChannel(channelState.getChannelCode()); + pumpPositionCache(channelState); + PreFill preFill = preFillService.lambdaQuery() + .eq(PreFill::getSolutionId, channelState.getSolutionId()) + .eq(PreFill::getConcentration, channelState.getConcentration()) + .one(); + DeviceCommand deviceCommand = getPumpMoveByCommandByChannel(channelState.getChannelCode(), preFill.getRevolutions()); commandFutureList.add(deviceCommandService.sendCommand(deviceCommand)); - AuditRecord auditRecord = new AuditRecord(deviceState.getCurrentUser().getId(), deviceState.getCurrentUser().getNickname(), channelState.getSolutionId(), - channelState.getSolutionName(), channelState.getConcentration(), channelState.getChannelCode().name(), channelState.getTargetVolume()); - auditRecordService.saveOrUpdate(auditRecord); + } CommandUtil.wait(commandFutureList); + for (ChannelState channelState : channelStateList) {//与缓存的位置比较计算加液量 + PreFill preFill = preFillService.lambdaQuery() + .eq(PreFill::getSolutionId, channelState.getSolutionId()) + .eq(PreFill::getConcentration, channelState.getConcentration()) + .one(); + handleCalculateActualDispensedVolume(channelState, preFill.getVolume(), preFill.getConcentration()); + } } catch (Exception e) { throw new RuntimeException(e); } @@ -282,8 +306,11 @@ public class ChannelCtrlService { List pumpMoveByCommandFutureList = new ArrayList<>(); for (ChannelState channelState : channelStateList) { pumpPositionCache(channelState); - Formulation formulation = formulationService.getOne(new LambdaQueryWrapper().eq(Formulation::getSolutionId, channelState.getSolutionId()) - .eq(Formulation::getConcentration, channelState.getConcentration()).eq(Formulation::getVolume, channelState.getTargetVolume()).last("limit 1")); + Formulation formulation = formulationService.lambdaQuery() + .eq(Formulation::getSolutionId, channelState.getSolutionId()) + .eq(Formulation::getConcentration, channelState.getConcentration()) + .eq(Formulation::getVolume, channelState.getTargetVolume()) + .one(); DeviceCommand deviceCommand = getPumpMoveByCommandByChannel(channelState.getChannelCode(), formulation.getRevolutions()); pumpMoveByCommandFutureList.add(deviceCommandService.sendCommand(deviceCommand)); } @@ -302,33 +329,29 @@ public class ChannelCtrlService { } /** - * 处理实际加液计算 + * 处理实际加液计算并更新 */ - private void handleCalculateActualDispensedVolume(List channelStateList) throws Exception { - for (ChannelState channelState : channelStateList) {//与缓存的位置比较计算加液量 - DeviceCommand currentPositionDeviceCommand = getPumpPositionCommandByChannel(channelState.getChannelCode()); - CommandFuture currentPositionCommandFuture = deviceCommandService.sendCommand(currentPositionDeviceCommand); - CommandUtil.wait(currentPositionCommandFuture); - Double currentPosition = currentPositionCommandFuture.getResponseResult().getJSONObject("data").getDouble("position"); - Formulation formulation = formulationService.getOne(new LambdaQueryWrapper().eq(Formulation::getSolutionId, channelState.getSolutionId()) - .eq(Formulation::getConcentration, channelState.getConcentration()).eq(Formulation::getVolume, channelState.getTargetVolume()).last("limit 1")); - double dispensedVolume = calculateActualSolutionDispensedVolume(channelState.getPumpPositionCache(), currentPosition, formulation); - double currentVolume = channelState.getCurrentVolume() - dispensedVolume;//剩余 - log.info("旧位置与新位置:{},{}", channelState.getPumpPositionCache(), currentPosition); - log.info("实际加液量:{}", dispensedVolume); - BigDecimal bd = BigDecimal.valueOf(currentVolume); - double roundedCurrentVolume = bd.setScale(2, RoundingMode.HALF_UP).doubleValue();//剩余保留2位 - if (roundedCurrentVolume < 0) { - roundedCurrentVolume = 0; - } - channelState.setCurrentVolume(roundedCurrentVolume); - Channel channel = channelService.getOne(new LambdaQueryWrapper<>(new Channel()).eq(Channel::getCode, channelState.getChannelCode())); - channel.setCurrentVolume(roundedCurrentVolume); - channelService.updateById(channel); - AuditRecord auditRecord = new AuditRecord(deviceState.getCurrentUser().getId(), deviceState.getCurrentUser().getNickname(), channelState.getSolutionId(), - channelState.getSolutionName(), formulation.getConcentration(), channelState.getChannelCode().name(), dispensedVolume);//记录审计 - auditRecordService.saveOrUpdate(auditRecord); + private void handleCalculateActualDispensedVolume(ChannelState channelState, double volume, double revs) throws Exception { + DeviceCommand currentPositionDeviceCommand = getPumpPositionCommandByChannel(channelState.getChannelCode()); + CommandFuture currentPositionCommandFuture = deviceCommandService.sendCommand(currentPositionDeviceCommand); + CommandUtil.wait(currentPositionCommandFuture); + Double currentPosition = currentPositionCommandFuture.getResponseResult().getJSONObject("data").getDouble("position"); + double dispensedVolume = calculateActualSolutionDispensedVolume(channelState.getPumpPositionCache(), currentPosition, volume, revs); + double currentVolume = channelState.getCurrentVolume() - dispensedVolume;//剩余 + log.info("旧位置与新位置:{},{}", channelState.getPumpPositionCache(), currentPosition); + log.info("实际加液量:{}", dispensedVolume); + BigDecimal bd = BigDecimal.valueOf(currentVolume); + double roundedCurrentVolume = bd.setScale(2, RoundingMode.HALF_UP).doubleValue();//剩余保留2位 + if (roundedCurrentVolume < 0) { + roundedCurrentVolume = 0; } + channelState.setCurrentVolume(roundedCurrentVolume); + Channel channel = channelService.getOne(new LambdaQueryWrapper<>(new Channel()).eq(Channel::getCode, channelState.getChannelCode())); + channel.setCurrentVolume(roundedCurrentVolume); + channelService.updateById(channel); + AuditRecord auditRecord = new AuditRecord(deviceState.getCurrentUser().getId(), deviceState.getCurrentUser().getNickname(), channelState.getSolutionId(), + channelState.getSolutionName(), channelState.getConcentration(), channelState.getChannelCode().name(), dispensedVolume);//记录审计 + auditRecordService.saveOrUpdate(auditRecord); } /** @@ -336,29 +359,17 @@ public class ChannelCtrlService { * * @param beforePosition 加液前旋转圈数 * @param afterPosition 加液后旋转圈数 - * @param formulation 配方对象,包含指定加液量及其对应的旋转圈数 - * - volume 目标加液量 - * - revolutions 目标加液对应的旋转圈数 - * @return double 实际出液量 + * @param volume 配方加液量 + * @param revs 配方加液对应的旋转圈数 */ - private double calculateActualSolutionDispensedVolume(Double beforePosition, Double afterPosition, Formulation formulation) { - if (beforePosition == null || afterPosition == null) { - throw new IllegalArgumentException("加液前/后位置参数不能为空"); - } - if (formulation == null - || formulation.getVolume() == null - || formulation.getRevolutions() == null) { - throw new IllegalArgumentException("Formulation 或其字段 volume/revolutions 不能为空"); - } + private double calculateActualSolutionDispensedVolume(double beforePosition, double afterPosition, double volume, double revs) { Integer pumpConversionFactor = systemConfigService.getValueByKeyToInteger(SystemConfigKey.PUMP_CONVERSION_FACTOR); double deltaRevolutions = (((afterPosition - beforePosition) / pumpConversionFactor)); - double targetVolume = formulation.getVolume(); - double targetRevs = formulation.getRevolutions(); - if (targetRevs == 0) { + if (revs == 0) { throw new IllegalArgumentException("Formulation.revolutions 不能为 0"); } // 实际出液量 = 差值圈数 * (目标加液量 ÷ 目标圈数) - BigDecimal bd = BigDecimal.valueOf(deltaRevolutions * (targetVolume / targetRevs)); + BigDecimal bd = BigDecimal.valueOf(deltaRevolutions * (volume / revs)); return bd.setScale(2, RoundingMode.HALF_UP).doubleValue(); } diff --git a/src/main/java/com/iflytop/handacid/common/mapper/PreFillMapper.java b/src/main/java/com/iflytop/handacid/common/mapper/PreFillMapper.java new file mode 100644 index 0000000..42fddca --- /dev/null +++ b/src/main/java/com/iflytop/handacid/common/mapper/PreFillMapper.java @@ -0,0 +1,14 @@ +package com.iflytop.handacid.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.iflytop.handacid.common.model.entity.Formulation; +import com.iflytop.handacid.common.model.entity.PreFill; +import org.apache.ibatis.annotations.Mapper; + + +/** + * 预充持久层接口 + */ +@Mapper +public interface PreFillMapper extends BaseMapper { +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/handacid/common/model/entity/PreFill.java b/src/main/java/com/iflytop/handacid/common/model/entity/PreFill.java new file mode 100644 index 0000000..1fce7d2 --- /dev/null +++ b/src/main/java/com/iflytop/handacid/common/model/entity/PreFill.java @@ -0,0 +1,27 @@ +package com.iflytop.handacid.common.model.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.iflytop.handacid.common.base.BaseEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@TableName("pre_fill") +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "预充配置") +public class PreFill extends BaseEntity { + + @Schema(description = "加液量(mL)") + private Double volume; + + @Schema(description = "溶液ID") + private Long solutionId; + + @Schema(description = "溶液浓度") + private Double concentration; + + @Schema(description = "对应转数") + private Double revolutions; + +} diff --git a/src/main/java/com/iflytop/handacid/common/service/PreFillService.java b/src/main/java/com/iflytop/handacid/common/service/PreFillService.java new file mode 100644 index 0000000..c04e7ba --- /dev/null +++ b/src/main/java/com/iflytop/handacid/common/service/PreFillService.java @@ -0,0 +1,17 @@ +package com.iflytop.handacid.common.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.iflytop.handacid.common.mapper.FormulationMapper; +import com.iflytop.handacid.common.mapper.PreFillMapper; +import com.iflytop.handacid.common.model.entity.Formulation; +import com.iflytop.handacid.common.model.entity.PreFill; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 预充 + */ +@Service +@RequiredArgsConstructor +public class PreFillService extends ServiceImpl { +} diff --git a/src/main/resources/sql/init.sql b/src/main/resources/sql/init.sql index 89128e6..85470e1 100644 --- a/src/main/resources/sql/init.sql +++ b/src/main/resources/sql/init.sql @@ -61,6 +61,17 @@ CREATE TABLE IF NOT EXISTS formulation ( update_time TEXT DEFAULT CURRENT_TIMESTAMP ); +--预充 +CREATE TABLE IF NOT EXISTS pre_fill ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + volume REAL,--加液量 + solution_id INTEGER,--溶液id + concentration REAL,--溶液浓度 + revolutions REAL,--对应转数 + create_time TEXT DEFAULT CURRENT_TIMESTAMP, + update_time TEXT DEFAULT CURRENT_TIMESTAMP +); + -- 溶液 CREATE TABLE IF NOT EXISTS solution ( id INTEGER PRIMARY KEY AUTOINCREMENT,