'use strict';
TABS.power = {
supported: false,
analyticsChanges: {},
};
TABS.power.initialize = function (callback) {
const self = this;
if (GUI.active_tab != 'power') {
GUI.active_tab = 'power';
// Disabled on merge into betaflight-configurator
//googleAnalytics.sendAppView('Power');
}
if (GUI.calibrationManager) {
GUI.calibrationManager.destroy();
}
if (GUI.calibrationManagerConfirmation) {
GUI.calibrationManagerConfirmation.destroy();
}
function load_status() {
MSP.send_message(MSPCodes.MSP_STATUS, false, false, load_voltage_meters);
}
function load_voltage_meters() {
MSP.send_message(MSPCodes.MSP_VOLTAGE_METERS, false, false, load_current_meters);
}
function load_current_meters() {
MSP.send_message(MSPCodes.MSP_CURRENT_METERS, false, false, load_current_meter_configs);
}
function load_current_meter_configs() {
MSP.send_message(MSPCodes.MSP_CURRENT_METER_CONFIG, false, false, load_voltage_meter_configs);
}
function load_voltage_meter_configs() {
MSP.send_message(MSPCodes.MSP_VOLTAGE_METER_CONFIG, false, false, load_battery_state);
}
function load_battery_state() {
MSP.send_message(MSPCodes.MSP_BATTERY_STATE, false, false, load_battery_config);
}
function load_battery_config() {
MSP.send_message(MSPCodes.MSP_BATTERY_CONFIG, false, false, load_html);
}
function load_html() {
$('#content').load("./tabs/power.html", process_html);
}
this.supported = semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_33);
if (!this.supported) {
load_html();
} else {
load_status();
}
function updateDisplay(voltageDataSource, currentDataSource) {
// voltage meters
if (FC.BATTERY_CONFIG.voltageMeterSource == 0) {
$('.boxVoltageConfiguration').hide();
} else {
$('.boxVoltageConfiguration').show();
}
if (!voltageDataSource) {
voltageDataSource = [];
for (let index = 0; index < FC.VOLTAGE_METER_CONFIGS.length; index++) {
voltageDataSource[index] = {
vbatscale: parseInt($(`input[name="vbatscale-${index}"]`).val()),
vbatresdivval: parseInt($(`input[name="vbatresdivval-${index}"]`).val()),
vbatresdivmultiplier: parseInt($(`input[name="vbatresdivmultiplier-${index}"]`).val()),
};
}
}
const templateVoltageMeter = $('#tab-power-templates .voltage-meters .voltage-meter');
const destinationVoltageMeter = $('.tab-power .voltage-meters');
destinationVoltageMeter.empty();
for (let index = 0; index < FC.VOLTAGE_METERS.length; index++) {
const elementVoltageMeter = templateVoltageMeter.clone();
$(elementVoltageMeter).attr('id', `voltage-meter-${index}`);
const message = i18n.getMessage(`powerVoltageId${FC.VOLTAGE_METERS[index].id}`);
$(elementVoltageMeter).find('.label').text(message);
destinationVoltageMeter.append(elementVoltageMeter);
elementVoltageMeter.hide();
if ((FC.BATTERY_CONFIG.voltageMeterSource == 1 && FC.VOLTAGE_METERS[index].id == 10) // TODO: replace hardcoded constants
|| (FC.BATTERY_CONFIG.voltageMeterSource == 2 && FC.VOLTAGE_METERS[index].id >= 50)) {
elementVoltageMeter.show();
}
}
const templateVoltageConfiguration = $('#tab-power-templates .voltage-configuration');
for (let index = 0; index < FC.VOLTAGE_METER_CONFIGS.length; index++) {
const destinationVoltageConfiguration = $(`#voltage-meter-${index} .configuration`);
const elementVoltageConfiguration = templateVoltageConfiguration.clone();
const attributeNames = ["vbatscale", "vbatresdivval", "vbatresdivmultiplier"];
for (let attributeName of attributeNames) {
$(elementVoltageConfiguration).find(`input[name="${attributeName}"]`).attr('name', `${attributeName}-${index}`);
}
destinationVoltageConfiguration.append(elementVoltageConfiguration);
$(`input[name="vbatscale-${index}"]`).val(voltageDataSource[index].vbatscale);
$(`input[name="vbatresdivval-${index}"]`).val(voltageDataSource[index].vbatresdivval);
$(`input[name="vbatresdivmultiplier-${index}"]`).val(voltageDataSource[index].vbatresdivmultiplier);
}
$('input[name="vbatscale-0"]').change(function () {
const value = parseInt($(this).val());
if (value !== voltageDataSource[0].vbatscale) {
self.analyticsChanges['PowerVBatUpdated'] = value;
}
});
// amperage meters
if (FC.BATTERY_CONFIG.currentMeterSource == 0) {
$('.boxAmperageConfiguration').hide();
} else {
$('.boxAmperageConfiguration').show();
}
if (!currentDataSource) {
currentDataSource = [];
for (let index = 0; index < FC.CURRENT_METER_CONFIGS.length; index++) {
currentDataSource[index] = {
scale: parseInt($(`input[name="amperagescale-${index}"]`).val()),
offset: parseInt($(`input[name="amperageoffset-${index}"]`).val()),
};
}
}
const templateAmperageMeter = $('#tab-power-templates .amperage-meters .amperage-meter');
const destinationAmperageMeter = $('.tab-power .amperage-meters');
destinationAmperageMeter.empty();
for (let index = 0; index < FC.CURRENT_METERS.length; index++) {
const elementAmperageMeter = templateAmperageMeter.clone();
$(elementAmperageMeter).attr('id', `amperage-meter-${index}`);
const message = i18n.getMessage(`powerAmperageId${FC.CURRENT_METERS[index].id}`);
$(elementAmperageMeter).find('.label').text(message);
destinationAmperageMeter.append(elementAmperageMeter);
elementAmperageMeter.hide();
if ((FC.BATTERY_CONFIG.currentMeterSource == 1 && FC.CURRENT_METERS[index].id == 10) // TODO: replace constants
|| (FC.BATTERY_CONFIG.currentMeterSource == 2 && FC.CURRENT_METERS[index].id == 80)
|| (FC.BATTERY_CONFIG.currentMeterSource == 3 && FC.CURRENT_METERS[index].id >= 50 && FC.CURRENT_METERS[index].id < 80)) {
elementAmperageMeter.show();
}
}
const templateAmperageConfiguration = $('#tab-power-templates .amperage-configuration');
for (let index = 0; index < FC.CURRENT_METER_CONFIGS.length; index++) {
const destinationAmperageConfiguration = $(`#amperage-meter-${index} .configuration`);
const elementAmperageConfiguration = templateAmperageConfiguration.clone();
const attributeNames = ["amperagescale", "amperageoffset"];
for (let attributeName of attributeNames) {
$(elementAmperageConfiguration).find(`input[name="${attributeName}"]`).attr('name', `${attributeName}-${index}`);
}
destinationAmperageConfiguration.append(elementAmperageConfiguration);
$(`input[name="amperagescale-${index}"]`).val(currentDataSource[index].scale);
$(`input[name="amperageoffset-${index}"]`).val(currentDataSource[index].offset);
}
$('input[name="amperagescale-0"]').change(function () {
if (FC.BATTERY_CONFIG.currentMeterSource === 1) {
let value = parseInt($(this).val());
if (value !== currentDataSource[0].scale) {
self.analyticsChanges['PowerAmperageUpdated'] = value;
}
}
});
$('input[name="amperagescale-1"]').change(function () {
if (FC.BATTERY_CONFIG.currentMeterSource === 2) {
let value = parseInt($(this).val());
if (value !== currentDataSource[1].scale) {
self.analyticsChanges['PowerAmperageUpdated'] = value;
}
}
});
if(FC.BATTERY_CONFIG.voltageMeterSource == 1 || FC.BATTERY_CONFIG.currentMeterSource == 1 || FC.BATTERY_CONFIG.currentMeterSource == 2) {
$('.calibration').show();
} else {
$('.calibration').hide();
}
}
function initDisplay() {
if (!TABS.power.supported) {
$(".tab-power").removeClass("supported");
return;
}
$(".tab-power").addClass("supported");
$("#calibrationmanagercontent").hide();
$("#calibrationmanagerconfirmcontent").hide();
// battery
const templateBatteryState = $('#tab-power-templates .battery-state .battery-state');
const destinationBatteryState = $('.tab-power .battery-state');
const elementBatteryState = templateBatteryState.clone();
$(elementBatteryState).find('.connection-state').attr('id', 'battery-connection-state');
$(elementBatteryState).find('.voltage').attr('id', 'battery-voltage');
$(elementBatteryState).find('.mah-drawn').attr('id', 'battery-mah-drawn');
$(elementBatteryState).find('.amperage').attr('id', 'battery-amperage');
destinationBatteryState.append(elementBatteryState.children());
const templateBatteryConfiguration = $('#tab-power-templates .battery-configuration');
const destinationBatteryConfiguration = $('.tab-power .battery .configuration');
const elementBatteryConfiguration = templateBatteryConfiguration.clone();
destinationBatteryConfiguration.append(elementBatteryConfiguration);
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) {
$('input[name="mincellvoltage"]').prop('step','0.01');
$('input[name="maxcellvoltage"]').prop('step','0.01');
$('input[name="warningcellvoltage"]').prop('step','0.01');
}
$('input[name="mincellvoltage"]').val(FC.BATTERY_CONFIG.vbatmincellvoltage);
$('input[name="maxcellvoltage"]').val(FC.BATTERY_CONFIG.vbatmaxcellvoltage);
$('input[name="warningcellvoltage"]').val(FC.BATTERY_CONFIG.vbatwarningcellvoltage);
$('input[name="capacity"]').val(FC.BATTERY_CONFIG.capacity);
const haveFc = (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_35) || (FC.CONFIG.boardType == 0 || FC.CONFIG.boardType == 2));
const batteryMeterTypes = [
i18n.getMessage('powerBatteryVoltageMeterTypeNone'),
i18n.getMessage('powerBatteryVoltageMeterTypeAdc'),
];
if (haveFc) {
batteryMeterTypes.push(i18n.getMessage('powerBatteryVoltageMeterTypeEsc'));
}
let batteryMeterType_e = $('select.batterymetersource');
for (let i = 0; i < batteryMeterTypes.length; i++) {
batteryMeterType_e.append(``);
}
// fill current
const currentMeterTypes = [
i18n.getMessage('powerBatteryCurrentMeterTypeNone'),
i18n.getMessage('powerBatteryCurrentMeterTypeAdc'),
];
if (haveFc) {
currentMeterTypes.push(i18n.getMessage('powerBatteryCurrentMeterTypeVirtual'));
currentMeterTypes.push(i18n.getMessage('powerBatteryCurrentMeterTypeEsc'));
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
currentMeterTypes.push(i18n.getMessage('powerBatteryCurrentMeterTypeMsp'));
}
}
let currentMeterType_e = $('select.currentmetersource');
for (let i = 0; i < currentMeterTypes.length; i++) {
currentMeterType_e.append(``);
}
updateDisplay(FC.VOLTAGE_METER_CONFIGS, FC.CURRENT_METER_CONFIGS);
batteryMeterType_e = $('select.batterymetersource');
let sourceschanged = false;
batteryMeterType_e.val(FC.BATTERY_CONFIG.voltageMeterSource);
batteryMeterType_e.change(function () {
FC.BATTERY_CONFIG.voltageMeterSource = parseInt($(this).val());
updateDisplay();
sourceschanged = true;
});
currentMeterType_e = $('select.currentmetersource');
currentMeterType_e.val(FC.BATTERY_CONFIG.currentMeterSource);
currentMeterType_e.change(function () {
FC.BATTERY_CONFIG.currentMeterSource = parseInt($(this).val());
updateDisplay();
sourceschanged = true;
});
function get_slow_data() {
MSP.send_message(MSPCodes.MSP_VOLTAGE_METERS, false, false, function () {
for (let i = 0; i < FC.VOLTAGE_METERS.length; i++) {
const elementVoltageMeters = $(`#voltage-meter-${i} .value`);
elementVoltageMeters.text(i18n.getMessage('powerVoltageValue', [FC.VOLTAGE_METERS[i].voltage]));
}
});
MSP.send_message(MSPCodes.MSP_CURRENT_METERS, false, false, function () {
for (let i = 0; i < FC.CURRENT_METERS.length; i++) {
const elementCurrentMeters = $(`#amperage-meter-${i} .value`);
elementCurrentMeters.text(i18n.getMessage('powerAmperageValue', [FC.CURRENT_METERS[i].amperage.toFixed(2)]));
}
});
MSP.send_message(MSPCodes.MSP_BATTERY_STATE, false, false, function () {
const elementPrefix = '#battery';
let elementMspBatteryState;
elementMspBatteryState = $(`${elementPrefix}-connection-state .value`);
elementMspBatteryState.text(FC.BATTERY_STATE.cellCount > 0
? i18n.getMessage('powerBatteryConnectedValueYes', [FC.BATTERY_STATE.cellCount])
: i18n.getMessage('powerBatteryConnectedValueNo'));
elementMspBatteryState = $(`${elementPrefix}-voltage .value`);
elementMspBatteryState.text(i18n.getMessage('powerVoltageValue', [FC.BATTERY_STATE.voltage]));
elementMspBatteryState = $(`${elementPrefix}-mah-drawn .value`);
elementMspBatteryState.text(i18n.getMessage('powerMahValue', [FC.BATTERY_STATE.mAhDrawn]));
elementMspBatteryState = $(`${elementPrefix}-amperage .value`);
elementMspBatteryState.text(i18n.getMessage('powerAmperageValue', [FC.BATTERY_STATE.amperage]));
});
}
//calibration manager
let calibrationconfirmed = false;
GUI.calibrationManager = new jBox('Modal', {
width: 400,
height: 230,
closeButton: 'title',
animation: false,
attach: $('#calibrationmanager'),
title: i18n.getMessage('powerCalibrationManagerTitle'),
content: $('#calibrationmanagercontent'),
onCloseComplete: function() {
if (!calibrationconfirmed) {
TABS.power.initialize();
}
},
});
GUI.calibrationManagerConfirmation = new jBox('Modal', {
width: 400,
height: 230,
closeButton: 'title',
animation: false,
attach: $('#calibrate'),
title: i18n.getMessage('powerCalibrationManagerConfirmationTitle'),
content: $('#calibrationmanagerconfirmcontent'),
onCloseComplete: function() {
GUI.calibrationManager.close();
},
});
$('a.calibrationmanager').click(function() {
if (FC.BATTERY_CONFIG.voltageMeterSource == 1 && FC.BATTERY_STATE.voltage > 0.1){
$('.vbatcalibration').show();
} else {
$('.vbatcalibration').hide();
}
if ((FC.BATTERY_CONFIG.currentMeterSource == 1 || FC.BATTERY_CONFIG.currentMeterSource == 2) && FC.BATTERY_STATE.amperage > 0.1) {
$('.amperagecalibration').show();
} else {
$('.amperagecalibration').hide();
}
if (FC.BATTERY_STATE.cellCount == 0) {
$('.vbatcalibration').hide();
$('.amperagecalibration').hide();
$('.calibrate').hide();
$('.nocalib').show();
} else {
$('.calibrate').show();
$('.nocalib').hide();
}
if (sourceschanged) {
$('.srcchange').show();
$('.vbatcalibration').hide();
$('.amperagecalibration').hide();
$('.calibrate').hide();
$('.nocalib').hide();
} else {
$('.srcchange').hide();
}
});
$('input[name="vbatcalibration"]').val(0);
$('input[name="amperagecalibration"]').val(0);
let vbatscalechanged = false;
let amperagescalechanged = false;
let vbatnewscale = 0;
let amperagenewscale = 0;
$('a.calibrate').click(function() {
if (FC.BATTERY_CONFIG.voltageMeterSource == 1) {
const vbatcalibration = parseFloat($('input[name="vbatcalibration"]').val());
if (vbatcalibration != 0) {
vbatnewscale = Math.round(FC.VOLTAGE_METER_CONFIGS[0].vbatscale * (vbatcalibration / FC.VOLTAGE_METERS[0].voltage));
if (vbatnewscale >= 10 && vbatnewscale <= 255) {
FC.VOLTAGE_METER_CONFIGS[0].vbatscale = vbatnewscale;
vbatscalechanged = true;
}
}
}
const ampsource = FC.BATTERY_CONFIG.currentMeterSource;
if (ampsource == 1 || ampsource == 2) {
const amperagecalibration = parseFloat($('input[name="amperagecalibration"]').val());
const amperageoffset = FC.CURRENT_METER_CONFIGS[ampsource - 1].offset / 1000;
if (amperagecalibration != 0) {
if (FC.CURRENT_METERS[ampsource - 1].amperage != amperageoffset && amperagecalibration != amperageoffset) {
amperagenewscale = Math.round(FC.CURRENT_METER_CONFIGS[ampsource - 1].scale *
((FC.CURRENT_METERS[ampsource - 1].amperage - amperageoffset) / (amperagecalibration - amperageoffset)));
if (amperagenewscale > -16000 && amperagenewscale < 16000 && amperagenewscale != 0) {
FC.CURRENT_METER_CONFIGS[ampsource - 1].scale = amperagenewscale;
amperagescalechanged = true;
}
}
}
}
if (vbatscalechanged || amperagescalechanged) {
if (vbatscalechanged) {
$('.vbatcalibration').show();
} else {
$('.vbatcalibration').hide();
}
if (amperagescalechanged) {
$('.amperagecalibration').show();
} else {
$('.amperagecalibration').hide();
}
$('output[name="vbatnewscale"').val(vbatnewscale);
$('output[name="amperagenewscale"').val(amperagenewscale);
$('a.applycalibration').click(function() {
if (vbatscalechanged) {
self.analyticsChanges['PowerVBatUpdated'] = 'Calibrated';
}
if (amperagescalechanged) {
self.analyticsChanges['PowerAmperageUpdated'] = 'Calibrated';
}
calibrationconfirmed = true;
GUI.calibrationManagerConfirmation.close();
updateDisplay(FC.VOLTAGE_METER_CONFIGS, FC.CURRENT_METER_CONFIGS);
$('.calibration').hide();
});
$('a.discardcalibration').click(function() {
GUI.calibrationManagerConfirmation.close();
});
} else {
GUI.calibrationManagerConfirmation.close();
}
});
$('a.save').click(function () {
for (let index = 0; index < FC.VOLTAGE_METER_CONFIGS.length; index++) {
FC.VOLTAGE_METER_CONFIGS[index].vbatscale = parseInt($(`input[name="vbatscale-${index}"]`).val());
FC.VOLTAGE_METER_CONFIGS[index].vbatresdivval = parseInt($(`input[name="vbatresdivval-${index}"]`).val());
FC.VOLTAGE_METER_CONFIGS[index].vbatresdivmultiplier = parseInt($(`input[name="vbatresdivmultiplier-${index}"]`).val());
}
for (let index = 0; index < FC.CURRENT_METER_CONFIGS.length; index++) {
FC.CURRENT_METER_CONFIGS[index].scale = parseInt($(`input[name="amperagescale-${index}"]`).val());
FC.CURRENT_METER_CONFIGS[index].offset = parseInt($(`input[name="amperageoffset-${index}"]`).val());
}
FC.BATTERY_CONFIG.vbatmincellvoltage = parseFloat($('input[name="mincellvoltage"]').val());
FC.BATTERY_CONFIG.vbatmaxcellvoltage = parseFloat($('input[name="maxcellvoltage"]').val());
FC.BATTERY_CONFIG.vbatwarningcellvoltage = parseFloat($('input[name="warningcellvoltage"]').val());
FC.BATTERY_CONFIG.capacity = parseInt($('input[name="capacity"]').val());
analytics.sendSaveAndChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges, 'power');
save_power_config();
});
GUI.interval_add('setup_data_pull_slow', get_slow_data, 200, true); // 5hz
}
function save_power_config() {
function save_battery_config() {
MSP.send_message(MSPCodes.MSP_SET_BATTERY_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_BATTERY_CONFIG), false, save_voltage_config);
}
function save_voltage_config() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
mspHelper.sendVoltageConfig(save_amperage_config);
} else {
MSP.send_message(MSPCodes.MSP_SET_VOLTAGE_METER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_VOLTAGE_METER_CONFIG), false, save_amperage_config);
}
}
function save_amperage_config() {
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_36)) {
mspHelper.sendCurrentConfig(save_to_eeprom);
} else {
MSP.send_message(MSPCodes.MSP_SET_CURRENT_METER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_CURRENT_METER_CONFIG), false, save_to_eeprom);
}
}
function save_to_eeprom() {
MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, save_completed);
}
function save_completed() {
GUI.log(i18n.getMessage('configurationEepromSaved'));
TABS.power.initialize();
}
save_battery_config();
}
function process_html() {
initDisplay();
self.analyticsChanges = {};
// translate to user-selected language
i18n.localizePage();
GUI.content_ready(callback);
}
};
TABS.power.cleanup = function (callback) {
if (callback) callback();
if (GUI.calibrationManager) {
GUI.calibrationManager.destroy();
}
if (GUI.calibrationManagerConfirmation) {
GUI.calibrationManagerConfirmation.destroy();
}
};