package com.bgy.autosale.helpers; import android.os.Handler; import android.os.Message; import android.util.Log; import com.bgy.autosale.App; import com.bgy.autosale.Constant; import com.bgy.autosale.IceCreamDeviceConstants; import com.bgy.autosale.R; import com.bgy.autosale.entitys.MakeIceCreamBean; import com.bgy.autosale.entitys.Result; import com.bgy.autosale.interfaces.Callback; import com.bgy.autosale.interfaces.FlavorUiCallback; import com.bgy.autosale.interfaces.OnCheckListener; import com.bgy.autosale.interfaces.OnCleanListener; import com.bgy.autosale.interfaces.OnTemperatureListener; import com.bgy.autosale.interfaces.RadarCallback; import com.bgy.autosale.interfaces.SendCallback; import com.bgy.autosale.plc.BasePlcAgreement; import com.bgy.autosale.plc.IceCreamAgreement; import com.bgy.autosale.utils.IceCreamErrorUtils; import com.bgy.autosale.utils.PlcLog; import com.bgy.autosale.utils.SPUtils; import com.hboxs.base_library.constant.Name; import com.hboxs.base_library.event.ApiMessageEvent; import com.hboxs.base_library.event.ErrorApiMessageEvent; import com.hboxs.base_library.util.LogUtils; import com.hboxs.base_library.util.SharedPreferencesUtils; import com.orhanobut.hawk.Hawk; import org.greenrobot.eventbus.EventBus; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; import io.reactivex.android.schedulers.AndroidSchedulers; /** * Created by cjx on 2020-08-19 * 说明: */ public class CommunicationHelper { private volatile static CommunicationHelper helper; private final String TAG = "COMMUNICATION"; private IceCreamAgreement agreement; private Callback> statusCallback; private Callback orderStatusCallback; private HashSet uiCallbacks = new HashSet<>(); private Callback deviceMessageCallback = null; private RadarCallback radarCallback = null; private OnTemperatureListener temperatureListener = null; private OnCleanListener cleanListener = null; private OnCheckListener checkListener = null; private LinkedList iceCreamOrders; private MakeIceCreamBean makingIceCream; private volatile boolean temperatureLock = false; private int manualAction = 0; private boolean isFirstConnect = true; // private boolean deviceError = false; private boolean deviceConnect = false; private int[] deviceStatus = null; private int currentTemperature = -1000; private int prevControlCode = 0; // 控制模式, 1=自动,2=手动 private int prevWorkCode = 0; // 工作状态, 0001:待机, 0002:运行中 private int prevDeviceCode = 0; // 设备状态, 1=正常,2=异常 private int prevErrorCode1 = -1; // 设备状态详情 private int prevErrorCode2 = -1; // 设备状态详情 private String detailMessage = null; private int makeProcess = 0; private int[] stockUpdateState = new int[]{-1, -1, -1, -1, -1, -1, -1, -1}; private Handler timeOutHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { if (makingIceCream != null) { // TODO 用户取餐超时,可以在云端通知商家提醒用户取餐 } return false; } }); private Handler heartHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { // 设备的心跳 heartHandler.sendEmptyMessageDelayed(0, 3550000); // TODO 这里可以同步设备的状态到云端 return false; } }); public static CommunicationHelper getInstance() { if (helper == null) { synchronized (CommunicationHelper.class) { if (helper == null) { helper = new CommunicationHelper(); } } } return helper; } private CommunicationHelper() { agreement = IceCreamAgreement.getInstance(); // TODO 此处处理雪糕的制作状态过程,可以同步信息到云端,监听设备的实时状态 agreement.setOrderCallback(new Callback>() { @Override public void onResult(Result result) { if (makingIceCream == null) { return; } int size = iceCreamOrders == null ? 0 : iceCreamOrders.size(); boolean canCallBack = true; switch (result.code) { case BasePlcAgreement.RESULT_CODE_ORDER_ERROR: // 下单失败 makingIceCream.orderStatus = MakeIceCreamBean.STATUS_ERROR; log(App.app.getString(R.string.making_error)); refundOrder(); break; case BasePlcAgreement.RESULT_CODE_ORDER_CHILD_PREPARE: // 出餐中 if (size > 0) { iceCreamOrders.poll(); } log(App.app.getString(R.string.making_ing)); makingIceCream.orderStatus = MakeIceCreamBean.STATUS_MAKING; break; case BasePlcAgreement.RESULT_CODE_ORDER_CHILD_OUT: // 待取餐 log(App.app.getString(R.string.making_taking)); makingIceCream.orderStatus = MakeIceCreamBean.STATUS_TAKING; timeOutHandler.sendEmptyMessageDelayed(0, 60000); break; case BasePlcAgreement.RESULT_CODE_ORDER_CHILD_FINISH: // 已取餐 log(App.app.getString(R.string.making_taked)); makingIceCream.orderStatus = MakeIceCreamBean.STATUS_TAKED; break; case BasePlcAgreement.RESULT_CODE_ORDER_COMPLETE: // 订单完成 makingIceCream = null; if (iceCreamOrders != null) { if (iceCreamOrders.isEmpty()) { iceCreamOrders = null; log(App.app.getString(R.string.making_finish)); } else { log(String.format(App.app.getString(R.string.making_next), size)); canCallBack = false; startIceCreamOrder(); } } break; } if (orderStatusCallback != null && canCallBack) { orderStatusCallback.onResult(new Result<>(result.code, null, result.message)); } } }); // 设置设备状态监听 agreement.setStatusListener(new Callback>() { @Override public void onResult(Result result) { if (result == null) { return; } switch (result.code) { case BasePlcAgreement.PLC_HEART_CONNECT: log(App.app.getString(R.string.mcu_connect)); deviceConnect = true; if (statusCallback != null) { statusCallback.onResult(new Result<>(BasePlcAgreement.PLC_HEART_CONNECT, false, null)); } for (FlavorUiCallback uiCallback : uiCallbacks) { if (uiCallback != null) { uiCallback.deviceStatusChangeCallback(true, result.data, detailMessage); } } if (isFirstConnect) { isFirstConnect = false; // 获取MCU功能版本,低版本设备不支持 agreement.sendControl(IceCreamDeviceConstants.ORDER_MCU_VERSION, new SendCallback() { @Override public void callBack(boolean ok, int[] result) { if (ok && result.length > 1) { App.app.mcuVersion = result[1]; } } }); } break; case BasePlcAgreement.PLC_HEART_DISCONNECT: log(App.app.getString(R.string.mcu_disconnect)); agreement.disConnect(new Exception("disconnect...")); deviceConnect = false; if (statusCallback != null) { statusCallback.onResult(new Result<>(BasePlcAgreement.PLC_HEART_DISCONNECT, false, null)); } for (FlavorUiCallback uiCallback : uiCallbacks) { if (uiCallback != null) { uiCallback.deviceStatusChangeCallback(false, result.data, null); } } break; case BasePlcAgreement.PLC_HEART_REPORT: if (result.data != null) { deviceStatus = result.data; if (App.app.unCheckStatus) { deviceStatus[2] = 1; } IceCreamErrorUtils.getInstance().bindStatus(deviceStatus); if (deviceStatus[0] == 1 && deviceStatus[2] == 1) { SharedPreferencesUtils.setParam("open", 1); } else { SharedPreferencesUtils.setParam("open", 0); } parserDeviceStatus(); if (IceCreamErrorUtils.getInstance().getErrorMessage() != null) { LogUtils.logWrite("机器报警了:"+IceCreamErrorUtils.getInstance().getErrorMessage()); String[] parts = IceCreamErrorUtils.getInstance().getErrorMessage().split(","); HashSet tempSet = new HashSet<>(); for (String part : parts) { String[] subparts = part.split("-"); // 对每个部分再根据破折号分隔 String item = subparts[0]; // 分隔后的第一部分 String number = subparts[1]; // 分隔后的第二部分 Log.d(TAG, "onResultsubparts: Item: " + item + ", Number: " + number); if (itemSet.add(item)){ // EventBus.getDefault().post(new ErrorApiMessageEvent(Name.WARNING_ALARM, item, number));//这里上传报警 Log.d("上传报警", "onResult: 上传报警111:"+item); shouldClearItemSet = false; }else { shouldClearItemSet=true; } tempSet.add(item); } Log.d("上传报警", "onResult: 上传报警112: "+itemSet+shouldClearItemSet); if (shouldClearItemSet) { itemSet.clear(); // 如果所有的item都已经存在,清空itemSet itemSet.addAll(tempSet); // 更新itemSet为tempSet的值 Log.d(TAG, "上传报警111: 清除"); } } else { EventBus.getDefault().post(new ApiMessageEvent("eliminate", null)); } } break; } } }); // 监听即使状态改变 agreement.setImmediateCallbak(new Callback() { @Override public void onResult(int[] content) { parserImmediateStatus(content); } }); agreement.connect(0, 9527); } private static final HashSet itemSet = new HashSet<>(); // private static final boolean shouldClearItemSet = true; // 退款 private void refundOrder() { synchronized (CommunicationHelper.class) { // 制作中的雪糕或者当前待制作的雪糕为空 if (makingIceCream == null || iceCreamOrders == null) { return; } if (!iceCreamOrders.contains(makingIceCream)) { // 当前待制作雪糕已经移除了当前制作中的雪糕, 则需要加回去 if (makingIceCream.orderStatus != MakeIceCreamBean.STATUS_TAKING && makingIceCream.orderStatus != MakeIceCreamBean.STATUS_TAKED) { iceCreamOrders.add(0, makingIceCream); } } // TODO 这里处理退款逻辑,需要退款的雪糕在 iceCreamOrders 内 makingIceCream = null; iceCreamOrders = null; } } public void changeTestMode() { App.app.unCheckStatus = true; agreement.setTestMode(); if (deviceStatus != null) { deviceStatus[2] = 1; parserDeviceStatus(); } } // 开始出雪糕 private void startIceCreamOrder() { MakeIceCreamBean detail = iceCreamOrders == null || iceCreamOrders.isEmpty() ? null : iceCreamOrders.peek(); if (detail != null) { Log.d(TAG, "setDishStatusListener4: "); makingIceCream = detail; try { Log.d(TAG, "setDishStatusListener5: "); IceCreamAgreement.Order iceCream = new IceCreamAgreement.Order(detail, detail.makeCodes[0], detail.makeCodes[1], detail.makeCodes[2]); Log.d(TAG, "setDishStatusListener6: "+iceCream); if (manualAction > 0) { Log.d(TAG, "setDishStatusListener7: "); agreement.setMakeOrderByManual(iceCream); sendControl(manualAction, detail.makeCodes[0], detail.makeCodes[1], detail.makeCodes[2], new SendCallback() { @Override public void callBack(boolean ok, int[] result) { } }); } else { Log.d(TAG, "setDishStatusListener8: "); agreement.setMakeOrderByManual(null); agreement.sendOrder(iceCream); } log(App.app.getString(R.string.making_out_flavor) + " > " + iceCream); } catch (Exception e) { Log.d(TAG, "setDishStatusListener9: "+e.getMessage()); e.printStackTrace(); PlcLog.getInstance().e_s(TAG, e); refundOrder(); } } else { Log.d(TAG, "setDishStatusListener10: "); makingIceCream = null; iceCreamOrders = null; } } public void destroy() { agreement.disConnect(new Exception("finish")); } // 首次加载商品信息 更新库存 public void setDataReally() { synchronized (CommunicationHelper.class) { for (int i = 0; i < 8; i++) { stockUpdateState[i] = -1; } if (deviceStatus != null) { parserDeviceStatusDetail(); } } } public void setMakingIceCreams(LinkedList iceCreamOrders) { this.iceCreamOrders = iceCreamOrders; } public void setDeviceStatusListener(Callback> statusCallback) { this.statusCallback = statusCallback; if (statusCallback == null) { return; } if (!deviceConnect) { statusCallback.onResult(new Result<>(BasePlcAgreement.PLC_HEART_DISCONNECT, false, null)); } if (deviceStatus != null) { parserDeviceStatus(); } } public void setDishStatusListener(Callback orderStatusCallback, int manualAction) { this.orderStatusCallback = orderStatusCallback; this.manualAction = manualAction; Log.d(TAG, "setDishStatusListener0: "); if (orderStatusCallback == null) { Log.d(TAG, "setDishStatusListener1: "); if (manualAction == -1) { refundOrder(); Log.d(TAG, "setDishStatusListener2: "); } return; } Log.d(TAG, "setDishStatusListener3: "); startIceCreamOrder(); } public void setDeviceMessageCallback(Callback messageCallback) { this.deviceMessageCallback = messageCallback; } public MakeIceCreamBean getMakingIceCream() { return makingIceCream; } public LinkedList getMakingIceCreams() { if (iceCreamOrders == null) { iceCreamOrders = new LinkedList<>(); } return iceCreamOrders; } public void addFlavorUiCallback(FlavorUiCallback uiCallback) { this.uiCallbacks.add(uiCallback); if (deviceStatus == null) { uiCallback.deviceStatusChangeCallback(false, null, null); return; } detailMessage = IceCreamErrorUtils.getInstance().getErrorMessage(); uiCallback.deviceStatusChangeCallback(deviceConnect, deviceStatus, detailMessage); } public void removeFlavorUiCallback(FlavorUiCallback uiCallback) { this.uiCallbacks.remove(uiCallback); } public void setRadarCallback(RadarCallback callback) { this.radarCallback = callback; } public void setOnTemperatureListener(OnTemperatureListener listener) { this.temperatureListener = listener; if (temperatureListener != null && currentTemperature != -1000) { temperatureListener.onTemperatureChange(currentTemperature); } } public void setOnCheckListener(OnCheckListener listener) { this.checkListener = listener; } public void setOnCleanListener(OnCleanListener listener) { this.cleanListener = listener; } // 发送控制指令 public void sendControl(int order, SendCallback callback) { sendControl(order, 0, 0, 0, callback); } public void sendControl(int order, int p1, int p2, int p3, SendCallback callback) { agreement.sendControl(order, p1, p2, p3, callback); } // 修改参数 public void sendModifyParams(int order, int param, SendCallback callback) { agreement.modifyParams(order, param, callback); } // 设备是否正常 public boolean canGenerateOrder() { return agreement != null && agreement.isNormal() && agreement.isFree(); } public boolean isDeviceNormal() { return agreement != null && agreement.isNormal(); } public String getWhyCanOrderText() { StringBuilder stringBuilder = new StringBuilder(); if (!agreement.isAuto()) { stringBuilder.append(App.app.getString(R.string.plc_errTip1)); } if (!agreement.isDeviceNoErr()) { if (stringBuilder.toString().length() > 1) { stringBuilder.append(","); } stringBuilder.append(App.app.getString(R.string.plc_errTip2)); } if (!agreement.isDeviceFree()) { if (stringBuilder.toString().length() > 1) { stringBuilder.append(","); } stringBuilder.append(App.app.getString(R.string.plc_errTip3)); } if (!agreement.isDeviceDoorNoWarn()) { if (stringBuilder.toString().length() > 1) { stringBuilder.append(","); } stringBuilder.append(App.app.getString(R.string.plc_errTip4)); } return stringBuilder.toString(); } // 解析设备状态 private void parserDeviceStatus() { if (deviceStatus[3] == BasePlcAgreement.PLC_DOOR_EMPTY) { timeOutHandler.removeMessages(0); } boolean deviceNormal; int controlCode = deviceStatus[0]; // 控制模式, 1=自动,2=手动 int workCode = deviceStatus[1]; // 工作状态, 0001:待机, 0002:运行中 int deviceCode = deviceStatus[2]; // 设备状态, 1=正常,2=异常 int errorCode1 = deviceStatus[4]; // 设备状态详情 int errorCode2 = deviceStatus[5]; // 设备状态详情 int process = deviceStatus[6]; // 当前制作流程 if (deviceStatus.length > 7) { int deviceMessage = deviceStatus[7]; if (deviceMessageCallback != null) { deviceMessageCallback.onResult(deviceMessage); } } deviceNormal = controlCode == BasePlcAgreement.PLC_CONTROL_AUTO && deviceCode == BasePlcAgreement.PLC_DEVICE_NORMAL; String errorMessage = parserDeviceStatusDetail(); if (errorMessage != null) { errorMessage = String.format(App.app.getString(R.string.error_contact_format), errorMessage, controlCode + "." + deviceCode + "." + errorCode1 + "." + errorCode2); } else if (!deviceNormal) { errorMessage = String.format(App.app.getString(R.string.error_contact_format), App.app.getString(R.string.error_wait), controlCode + "." + deviceCode + "." + errorCode1 + "." + errorCode2); } if (IceCreamErrorUtils.getInstance().isGaoya()) { deviceNormal = false; } if (statusCallback != null) { statusCallback.onResult(new Result<>(BasePlcAgreement.PLC_HEART_REPORT, deviceNormal, errorMessage)); } if (errorCode1 != prevErrorCode1 || errorCode2 != prevErrorCode2) { detailMessage = IceCreamErrorUtils.getInstance().getErrorMessage(); log(String.format(App.app.getString(R.string.mcu_waring_message), detailMessage, errorMessage)); } for (FlavorUiCallback uiCallback : uiCallbacks) { if (uiCallback != null) { uiCallback.deviceStatusChangeCallback(true, deviceStatus, detailMessage); } } // 处理制作流程 if (makeProcess != process) { if (makeProcess == 2 && process == 3) { // 出杯 StockHelper.getInstance().outCup(); log(App.app.getString(R.string.making_out_cup)); } else if (makeProcess == 3 && process > 3 && process != 9) { // 出雪糕 StockHelper.getInstance().outFlavor(); log(App.app.getString(R.string.making_out_flavor)); } makeProcess = process; } if (prevControlCode == controlCode && prevDeviceCode == deviceCode && prevWorkCode == workCode && prevErrorCode1 == errorCode1 && prevErrorCode2 == errorCode2) { return; } prevControlCode = controlCode; prevDeviceCode = deviceCode; prevWorkCode = workCode; prevErrorCode1 = errorCode1; prevErrorCode2 = errorCode2; heartHandler.removeMessages(0); heartHandler.sendEmptyMessageDelayed(0, 8000); } public int getDeviceStatus(int position) { if (!deviceConnect || deviceStatus == null) { return 0; } return deviceStatus[position]; } // 即时状态改变监听 private void parserImmediateStatus(int[] content) { if (content == null || content.length < 2) { return; } switch (content[0]) { case 1: // 雷达 // 播放揽客语音 if (radarCallback != null) { radarCallback.isCheck(content[1] == 1); } break; case 2: // 温度 currentTemperature = content[1]; if (currentTemperature > 43 || currentTemperature < 10) { if (!temperatureLock) { temperatureLock = true; AndroidSchedulers.mainThread().scheduleDirect(new Runnable() { @Override public void run() { temperatureLock = false; } }, 1800, TimeUnit.SECONDS); } } if (temperatureListener != null) { temperatureListener.onTemperatureChange(currentTemperature); } break; case 3: // 点检结果 1 = 点检中 2 = 点检成功, 3 = 点检失败 if (checkListener != null) { checkListener.onCheck(content[1]); } break; case 4: // 清洗状态 1 = 已清洗 if (cleanListener != null) { cleanListener.cleanStatus(content[1]); } break; } } // 解析设备状态明细 private String parserDeviceStatusDetail() { String errMessage = null; boolean milkEmpty = false; boolean cupEmpty = false; if (IceCreamErrorUtils.getInstance().isMilkEmpty()) { errMessage = App.app.getString(R.string.error_milk_slurry_empty); milkEmpty = true; } else if (IceCreamErrorUtils.getInstance().isCupStockEmpty()) { errMessage = App.app.getString(R.string.error_cup_empty); cupEmpty = true; } else if (IceCreamErrorUtils.getInstance().isDoorOpen()) { errMessage = App.app.getString(R.string.error_door_un_close); } else if (IceCreamErrorUtils.getInstance().isSleep()) { errMessage = App.app.getString(R.string.error_power_saving); } if (IceCreamErrorUtils.getInstance().isGaoya()) { errMessage = App.app.getString(R.string.error_high_pressure); } // 更新各类库存 updateFlavorStock(milkEmpty); updateCupStock(cupEmpty); return errMessage; } // 更新奶浆的库存 private void updateFlavorStock(boolean empty) { boolean stockWarning = IceCreamErrorUtils.getInstance().isMilkStockWarning(); if (!stockWarning && !empty) { // 开始清洗倒计时功能 CleanScheduleHelper.getInstance().startCleanSchedule(); } int stock; final String KEY_FLAVOR_STOCK_WARNING = "KEY_FLAVOR_STOCK_WARNING_2008"; if (empty) { if (stockUpdateState[0] == 0) { return; } stockUpdateState[0] = 0; stock = 0; } else if (stockWarning) { if (stockUpdateState[0] == 2) { return; } stockUpdateState[0] = 2; if (!SPUtils.getInstance(App.app).getBoolean(KEY_FLAVOR_STOCK_WARNING, false)) { SPUtils.getInstance(App.app).putBoolean(KEY_FLAVOR_STOCK_WARNING, true); // TODO 库存告警, 更新当前库存为告警时默认库存 stock = Constant.STOCK_FLAVOR_WARING_MAX_COUNT; } else { return; } } else { if (stockUpdateState[0] == 1) { return; } stockUpdateState[0] = 1; // 解除库存告警, 默认当前为最大库存 stock = 99999; SPUtils.getInstance(App.app).putBoolean(KEY_FLAVOR_STOCK_WARNING, false); } StockHelper.getInstance().saveStock(2, 1, stock); } // 更新杯子的库存 private void updateCupStock(boolean empty) { boolean stockWarning = IceCreamErrorUtils.getInstance().isCupStockWarning(); final String KEY_CUP_STOCK_WARNING = "KEY_CUP_STOCK_WARNING_2008"; int stock; if (empty) { if (stockUpdateState[1] == 0) { return; } stockUpdateState[1] = 0; stock = 0; } else if (stockWarning) { if (stockUpdateState[1] == 2) { return; } stockUpdateState[1] = 2; if (!SPUtils.getInstance(App.app).getBoolean(KEY_CUP_STOCK_WARNING, false)) { SPUtils.getInstance(App.app).putBoolean(KEY_CUP_STOCK_WARNING, true); stock = Constant.STOCK_WARING_MAX_COUNT + 1; // TODO 是否要提示库存报警信息,可以上传到云端 } else { return; } } else { if (stockUpdateState[1] == 1) { return; } stockUpdateState[1] = 1; stock = 99999; SPUtils.getInstance(App.app).putBoolean(KEY_CUP_STOCK_WARNING, false); } StockHelper.getInstance().saveStock(1, 1, stock); } private void log(String msg) { PlcLog.getInstance().e_s(TAG, msg); } }