grid-apps-cmms/src2/kiri/devices.js
2025-07-05 18:52:53 -04:00

382 lines
11 KiB
JavaScript

/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
import { $, h } from '../moto/webui.js';
import { api } from './api.js';
import { conf } from './conf.js';
import { space } from '../moto/space.js';
import { devices as devlist } from '../pack/devices.js';
import { settings, conf as setconf } from './settings.js';
export const device = {
clone: cloneDevice,
code: currentDeviceCode,
get: currentDeviceName,
set: selectDevice,
isBelt
};
export const devices = {
show: showDevices,
select: selectDevice,
refresh: updateDeviceList,
update_laser_state: updateLaserState
};
function isBelt() {
return setconf.get().device.bedBelt;
}
function currentDeviceName() {
return setconf.get().filter[api.mode.get()];
}
function currentDeviceCode() {
return setconf.get().devices[currentDeviceName()];
}
function getModeDevices() {
return Object.keys(devlist[ api.mode.get_lower() ]).sort();
}
export function showDevices() {
settings.sync.get().then(_showDevices);
}
function _showDevices() {
updateDeviceList();
api.modal.show('setup');
}
function updateDeviceList() {
renderDevices(getModeDevices());
}
function updateDeviceName(newname) {
let selected = api.device.get(),
devs = setconf.get().devices;
if (newname !== selected) {
devs[newname] = devs[selected];
delete devs[selected];
selectDevice(newname);
updateDeviceList();
}
}
function putLocalDevice(devicename, obj) {
setconf.get().devices[devicename] = obj;
setconf.save();
}
function removeLocalDevice(devicename) {
delete setconf.get().devices[devicename];
setconf.save();
settings.sync.put();
}
function isLocalDevice(devicename) {
return setconf.get().devices[devicename] ? true : false;
}
function getSelectedDevice() {
return api.device.get();
}
function selectDevice(devicename) {
if (isLocalDevice(devicename)) {
setDeviceCode(setconf.get().devices[devicename], devicename);
} else {
let code = devlist[api.mode.get_lower()][devicename];
if (code) {
setDeviceCode(code, devicename);
}
}
}
// only for local filters
function cloneDevice() {
let name = `${getSelectedDevice().replace(/\./g,' ')}`;
let code = api.clone(setconf.get().device);
code.mode = api.mode.get();
if (name.toLowerCase().indexOf('my ') >= 0) {
name = `${name} copy`;
} else {
name = `My ${name}`;
}
putLocalDevice(name, code);
setDeviceCode(code, name);
settings.sync.put();
}
function updateLaserState() {
const dev = setconf.get().device;
$('laser-on').style.display = dev.useLaser ? 'flex' : 'none';
$('laser-off').style.display = dev.useLaser ? 'flex' : 'none';
}
function setDeviceCode(code, devicename) {
api.event.emit('device.select', devicename);
try {
if (typeof(code) === 'string') code = js2o(code) || {};
let mode = api.mode.get(),
lmode = mode.toLowerCase(),
current = setconf.get(),
local = isLocalDevice(devicename),
dev = current.device = conf.device_from_code(code,mode),
dproc = current.devproc[devicename], // last process name for this device
newdev = dproc === undefined, // first time device is selected
predev = current.filter[mode], // previous device selection
chgdev = predev !== devicename; // device is changing
// fill missing device fields
conf.fill_cull_once(dev, conf.defaults[lmode].d);
// first time device use, add any print profiles and set to default if present
if (code.profiles) {
for (let profile of code.profiles) {
let profname = profile.processName;
// if no saved profile by that name for this mode...
if (!current.sproc[mode][profname]) {
console.log('adding profile', profname, 'to', mode);
current.sproc[mode][profname] = profile;
}
// if it's a new device, seed the new profile name as last profile
if (newdev && !current.devproc[devicename]) {
console.log('setting default profile for new device', devicename, 'to', profname);
current.devproc[devicename] = dproc = profname;
}
}
}
dev.new = false;
dev.deviceName = devicename;
let { platform, ui, uc } = api;
ui.deviceBelt.checked = dev.bedBelt;
ui.deviceRound.checked = dev.bedRound;
ui.deviceOrigin.checked = dev.ctOriginCenter || dev.originCenter || dev.bedRound;
ui.fwRetract.checked = dev.fwRetract;
// add extruder selection buttons
if (dev.extruders) {
let ext = api.lists.extruders = [];
dev.internal = 0;
for (let i=0; i<dev.extruders.length; i++) {
ext.push({id:i, name:i});
}
}
// disable editing for non-local devices
[
// ui.deviceName,
ui.gcodePre,
ui.gcodePost,
ui.bedDepth,
ui.bedWidth,
ui.maxHeight,
ui.useLaser,
ui.resolutionX,
ui.resolutionY,
ui.deviceOrigin,
ui.deviceRound,
ui.deviceBelt,
ui.fwRetract,
ui.deviceZMax,
ui.gcodeTime,
ui.gcodeFan,
ui.gcodeFeature,
ui.gcodeTrack,
ui.gcodeLayer,
ui.extFilament,
ui.extNozzle,
ui.spindleMax,
ui.gcodeSpindle,
ui.gcodeDwell,
ui.gcodeChange,
ui.gcodeFExt,
ui.gcodeSpace,
ui.gcodeStrip,
ui.gcodeLaserOn,
ui.gcodeLaserOff,
ui.laserMaxPower,
ui.extPrev,
ui.extNext,
ui.extAdd,
ui.extDel,
ui.extOffsetX,
ui.extOffsetY
].forEach(function(e) {
e.disabled = !local;
});
ui.deviceSave.disabled = !local;
ui.deviceDelete.disabled = !local;
ui.deviceRename.disabled = !local;
ui.deviceExport.disabled = !local;
ui.deviceAdd.style.display = mode === 'SLA' ? 'none' : '';
if (local) {
ui.deviceAdd.innerText = "copy";
ui.deviceDelete.style.display = '';
ui.deviceRename.style.display = '';
ui.deviceExport.style.display = '';
} else {
ui.deviceAdd.innerText = "customize";
ui.deviceDelete.style.display = 'none';
ui.deviceRename.style.display = 'none';
ui.deviceExport.style.display = 'none';
}
ui.deviceAdd.disabled = dev.noclone;
setconf.update_fields();
space.platform.setBelt(isBelt());
platform.update_size();
platform.update_origin();
platform.update();
updateLaserState();
// store current device name for this mode
current.filter[mode] = devicename;
// cache device record for this mode (restored in setMode)
current.cdev[mode] = dev;
if (dproc) {
// restore last process associated with this device
setconf.load(null, dproc);
} else {
setconf.update();
}
setconf.save();
if (isBelt()) {
// space.view.setHome(dev.bedBelt ? Math.PI/2 : 0, Math.PI / 2.5);
space.view.setHome(0, Math.PI / 2.5);
} else {
space.view.setHome(0);
}
// when changing devices, update focus on widgets
if (chgdev) {
setTimeout(api.space.set_focus, 0);
}
uc.refresh(1);
api.event.emit('device.selected', dev);
} catch (e) {
console.log({error:e, device:code, devicename});
api.show.alert(`invalid or deprecated device: "${devicename}"`, 10);
api.show.alert(`please select a new device`, 10);
throw e;
showDevices();
}
api.function.clear();
api.event.settings();
}
function renderDevices(devices) {
let selected = api.device.get() || devices[0],
features = api.feature,
devs = setconf.get().devices,
dfilter = typeof(features.device_filter) === 'function' ? features.device_filter : undefined;
for (let local in devs) {
if (!(devs.hasOwnProperty(local) && devs[local])) {
continue;
}
let dev = devs[local],
fdmCode = dev.cmd,
fdmMode = (api.mode.get() === 'FDM');
if (dev.mode ? (dev.mode === api.mode.get()) : (fdmCode ? fdmMode : !fdmMode)) {
devices.push(local);
}
};
devices = devices.sort();
let { event, ui } = api;
event.emit('devices.render', devices);
ui.deviceSave.onclick = function() {
event.emit('device.save');
api.function.clear();
setconf.save();
settings.sync.put();
showDevices();
api.modal.hide();
};
ui.deviceAdd.onclick = function() {
api.function.clear();
cloneDevice();
showDevices();
};
ui.deviceDelete.onclick = function() {
api.function.clear();
removeLocalDevice(getSelectedDevice());
selectDevice(getModeDevices()[0]);
showDevices();
};
ui.deviceRename.onclick = function() {
api.uc.prompt(`Rename "${selected}`, selected).then(newname => {
if (newname) {
updateDeviceName(newname);
setconf.save();
settings.sync.put();
showDevices();
} else {
showDevices();
}
});
};
ui.deviceExport.onclick = function(event) {
const record = {
version: kiri.version,
device: selected,
process: api.process.code(),
profiles: event.altKey ? settings.prof() : undefined,
code: devs[selected],
time: Date.now()
};
let exp = api.util.b64enc(record);
api.device.export(exp, selected, { event, record });
};
let dedup = {};
let list_cdev = [];
let list_mdev = [];
devices.forEach(function(device, index) {
// prevent device from appearing twice
// such as local name = standard device name
if (dedup[device]) {
return;
}
dedup[device] = device;
let loc = isLocalDevice(device);
if (dfilter && dfilter(device) === false) {
return;
}
if (loc) {
list_mdev.push(h.option(device));
} else {
list_cdev.push(h.option(device));
}
});
let dev_list = $('dev-list');
h.bind(dev_list, [
h.option({ _: '-- My Devices --', disabled: true }),
...list_mdev,
h.option({ _: '-- Stock Devices --', disabled: true }),
...list_cdev
]);
let dev_opts = [...dev_list.options].map(o => o.innerText);
dev_list.selectedIndex = dev_opts.indexOf(selected);
dev_list.onchange = ev => {
const seldev = dev_list.options[dev_list.selectedIndex];
selectDevice(seldev.innerText);
api.platform.layout();
}
selectDevice(selected);
}