mirror of
				https://github.com/Ysurac/openmptcprouter-feeds.git
				synced 2025-03-09 15:40:03 +00:00 
			
		
		
		
	Add luci-proto-modemmanager to add puk code and display device in Network->Interfaces
This commit is contained in:
		
							parent
							
								
									307d22341f
								
							
						
					
					
						commit
						6511494f1c
					
				
					 6 changed files with 489 additions and 0 deletions
				
			
		
							
								
								
									
										16
									
								
								luci-proto-modemmanager/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								luci-proto-modemmanager/Makefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
#
 | 
			
		||||
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
 | 
			
		||||
#
 | 
			
		||||
# This is free software, licensed under the Apache License, Version 2.0 .
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
include $(TOPDIR)/rules.mk
 | 
			
		||||
 | 
			
		||||
LUCI_TITLE:=Support for ModemManager
 | 
			
		||||
LUCI_DEPENDS:=+modemmanager
 | 
			
		||||
 | 
			
		||||
PKG_LICENSE:=Apache-2.0
 | 
			
		||||
 | 
			
		||||
include $(TOPDIR)/feeds/luci/luci.mk
 | 
			
		||||
 | 
			
		||||
# call BuildPackage - OpenWrt buildroot signature
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,101 @@
 | 
			
		|||
'use strict';
 | 
			
		||||
'require baseclass';
 | 
			
		||||
'require fs';
 | 
			
		||||
 | 
			
		||||
return baseclass.extend({
 | 
			
		||||
 | 
			
		||||
	_mmcliBin: '/usr/bin/mmcli',
 | 
			
		||||
 | 
			
		||||
	_emptyStringValue: '--',
 | 
			
		||||
 | 
			
		||||
	_parseIndex: function (dbusPath) {
 | 
			
		||||
		var index = dbusPath.split('/').slice(-1);
 | 
			
		||||
		return parseInt(index);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	_parseOutput: function (output) {
 | 
			
		||||
		try {
 | 
			
		||||
			return this._removeEmptyStrings(JSON.parse(output));
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	_removeEmptyStrings: function (obj) {
 | 
			
		||||
		if (obj == null) {
 | 
			
		||||
			return obj;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (typeof obj == 'string') {
 | 
			
		||||
			if (obj == this._emptyStringValue) {
 | 
			
		||||
				obj = null;
 | 
			
		||||
			}
 | 
			
		||||
		} else if (Array.isArray()) {
 | 
			
		||||
			obj = obj.map(L.bind(function (it) {
 | 
			
		||||
				return this._removeEmptyStrings(it);
 | 
			
		||||
			}, this));
 | 
			
		||||
		} else {
 | 
			
		||||
			var keys = Object.keys(obj);
 | 
			
		||||
			keys.forEach(L.bind(function (key) {
 | 
			
		||||
				obj[key] = this._removeEmptyStrings(obj[key]);
 | 
			
		||||
			}, this));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return obj;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getModems: function () {
 | 
			
		||||
		return fs.exec_direct(this._mmcliBin, [ '-L', '-J' ]).then(L.bind(function (res) {
 | 
			
		||||
			var json = this._parseOutput(res);
 | 
			
		||||
			if (json == null) {
 | 
			
		||||
				return [];
 | 
			
		||||
			}
 | 
			
		||||
			var modems = json['modem-list'];
 | 
			
		||||
			var tasks = [];
 | 
			
		||||
 | 
			
		||||
			modems.forEach(L.bind(function (modem) {
 | 
			
		||||
				var index = this._parseIndex(modem);
 | 
			
		||||
				if (!isNaN(index)) {
 | 
			
		||||
					tasks.push(this.getModem(index));
 | 
			
		||||
				}
 | 
			
		||||
			}, this));
 | 
			
		||||
			return Promise.all(tasks);
 | 
			
		||||
		}, this));
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getModem: function (index) {
 | 
			
		||||
		return fs.exec_direct(this._mmcliBin, [ '-m', index, '-J' ]).then(L.bind(function (modem) {
 | 
			
		||||
			return this._parseOutput(modem);
 | 
			
		||||
		}, this));
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getModemSims: function (modem) {
 | 
			
		||||
		var tasks = [];
 | 
			
		||||
		var simSlots = modem.generic['sim-slots'];
 | 
			
		||||
		var sim = modem.generic.sim;
 | 
			
		||||
		if (sim != null && !simSlots.includes(sim)) {
 | 
			
		||||
			simSlots.push(sim);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		simSlots.forEach(L.bind(function (modem) {
 | 
			
		||||
			var index = this._parseIndex(modem);
 | 
			
		||||
			if (!isNaN(index)) {
 | 
			
		||||
				tasks.push(this.getSim(index));
 | 
			
		||||
			}
 | 
			
		||||
		}, this));
 | 
			
		||||
		return Promise.all(tasks);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getSim: function (index) {
 | 
			
		||||
		return fs.exec_direct(this._mmcliBin, [ '-i', index, '-J' ]).then(L.bind(function (sim) {
 | 
			
		||||
			return this._parseOutput(sim);
 | 
			
		||||
		}, this));
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getModemLocation: function (modem) {
 | 
			
		||||
		var index = this._parseIndex(modem['dbus-path']);
 | 
			
		||||
		return fs.exec_direct(this._mmcliBin, [ '-m', index, '--location-get', '-J' ]).then(L.bind(function (location) {
 | 
			
		||||
			return this._parseOutput(location);
 | 
			
		||||
		}, this));
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,164 @@
 | 
			
		|||
'use strict';
 | 
			
		||||
'require fs';
 | 
			
		||||
'require form';
 | 
			
		||||
'require network';
 | 
			
		||||
'require modemmanager_helper as helper';
 | 
			
		||||
 | 
			
		||||
network.registerPatternVirtual(/^mobiledata-.+$/);
 | 
			
		||||
network.registerErrorCode('MM_CONNECT_FAILED', _('Connection attempt failed.'));
 | 
			
		||||
network.registerErrorCode('MM_CONNECT_IN_PROGRESS', _('Modem connection in progress. Please wait. This process will timeout after 2 minutes.'));
 | 
			
		||||
network.registerErrorCode('DEVICE_NOT_MANAGED', _('Device not managed by ModemManager.'));
 | 
			
		||||
network.registerErrorCode('INVALID_BEARER_LIST', _('Invalid bearer list. Possibly too many bearers created.  This protocol supports one and only one bearer.'));
 | 
			
		||||
network.registerErrorCode('UNKNOWN_METHOD', _('Unknown and unsupported connection method.'));
 | 
			
		||||
network.registerErrorCode('DISCONNECT_FAILED', _('Disconnection attempt failed.'));
 | 
			
		||||
network.registerErrorCode('MM_INVALID_ALLOWED_MODES_LIST', _('Unable to set allowed mode list.'));
 | 
			
		||||
network.registerErrorCode('MM_NO_PREFERRED_MODE_CONFIGURED', _('No preferred mode configuration found.'));
 | 
			
		||||
network.registerErrorCode('MM_NO_ALLOWED_MODE_CONFIGURED', _('No allowed mode configuration found.'));
 | 
			
		||||
network.registerErrorCode('MM_FAILED_SETTING_PREFERRED_MODE', _('Unable to set preferred mode.'));
 | 
			
		||||
 | 
			
		||||
return network.registerProtocol('modemmanager', {
 | 
			
		||||
	getI18n: function() {
 | 
			
		||||
		return _('ModemManager');
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getIfname: function() {
 | 
			
		||||
		return this._ubus('l3_device') || 'modemmanager-%s'.format(this.sid);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getOpkgPackage: function() {
 | 
			
		||||
		return 'modemmanager';
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	isFloating: function() {
 | 
			
		||||
		return true;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	isVirtual: function() {
 | 
			
		||||
		return true;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	getDevices: function() {
 | 
			
		||||
		return null;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	containsDevice: function(ifname) {
 | 
			
		||||
		return (network.getIfnameOf(ifname) == this.getIfname());
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	renderFormOptions: function(s) {
 | 
			
		||||
		var dev = this.getL3Device() || this.getDevice(), o;
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.ListValue, '_modem_device', _('Modem device'));
 | 
			
		||||
		o.ucioption = 'device';
 | 
			
		||||
		o.rmempty = false;
 | 
			
		||||
		o.load = function(section_id) {
 | 
			
		||||
			return helper.getModems().then(L.bind(function(devices) {
 | 
			
		||||
				for (var i = 0; i < devices.length; i++) {
 | 
			
		||||
					var generic = devices[i].modem.generic;
 | 
			
		||||
					this.value(generic.device,
 | 
			
		||||
						'%s - %s (%s)'.format(generic.manufacturer, generic.model, generic.device));
 | 
			
		||||
				}
 | 
			
		||||
				return form.Value.prototype.load.apply(this, [section_id]);
 | 
			
		||||
			}, this));
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'apn', _('APN'));
 | 
			
		||||
		o.validate = function(section_id, value) {
 | 
			
		||||
			if (value == null || value == '')
 | 
			
		||||
				return true;
 | 
			
		||||
 | 
			
		||||
			if (!/^[a-zA-Z0-9\-.]*[a-zA-Z0-9]$/.test(value))
 | 
			
		||||
				return _('Invalid APN provided');
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'pincode', _('PIN'));
 | 
			
		||||
		o.datatype = 'and(uinteger,minlength(4),maxlength(8))';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'pukcode', _('PUK'));
 | 
			
		||||
		o.datatype = 'and(uinteger,minlength(8),maxlength(8))';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.ListValue, 'auth', _('Authentication Type'));
 | 
			
		||||
		o.value('both', _('PAP/CHAP (both)'));
 | 
			
		||||
		o.value('pap', 'PAP');
 | 
			
		||||
		o.value('chap', 'CHAP');
 | 
			
		||||
		o.value('none', _('None'));
 | 
			
		||||
		o.default = 'none';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.ListValue, 'allowedmode', _('Allowed network technology'),
 | 
			
		||||
			_('Setting the allowed network technology.'));
 | 
			
		||||
		o.value('2g');
 | 
			
		||||
		o.value('3g');
 | 
			
		||||
		o.value('3g|2g');
 | 
			
		||||
		o.value('4g');
 | 
			
		||||
		o.value('4g|2g');
 | 
			
		||||
		o.value('4g|3g');
 | 
			
		||||
		o.value('4g|3g|2g');
 | 
			
		||||
		o.value('5g');
 | 
			
		||||
		o.value('5g|2g');
 | 
			
		||||
		o.value('5g|3g');
 | 
			
		||||
		o.value('5g|3g|2g');
 | 
			
		||||
		o.value('5g|4g');
 | 
			
		||||
		o.value('5g|4g|2g');
 | 
			
		||||
		o.value('5g|4g|3g');
 | 
			
		||||
		o.value('5g|4g|3g|2g');
 | 
			
		||||
		o.value('',_('any'));
 | 
			
		||||
		o.default = '';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.ListValue, 'preferredmode', _('Preferred network technology'),
 | 
			
		||||
			_('Setting the preferred network technology.'));
 | 
			
		||||
		o.value('2g');
 | 
			
		||||
		o.value('3g');
 | 
			
		||||
		o.value('4g');
 | 
			
		||||
		o.value('5g');
 | 
			
		||||
		o.value('none', _('None'));
 | 
			
		||||
		o.depends('allowedmode','3g|2g');
 | 
			
		||||
		o.depends('allowedmode','4g|2g');
 | 
			
		||||
		o.depends('allowedmode','4g|3g');
 | 
			
		||||
		o.depends('allowedmode','4g|3g|2g');
 | 
			
		||||
		o.depends('allowedmode','5g|2g');
 | 
			
		||||
		o.depends('allowedmode','5g|3g');
 | 
			
		||||
		o.depends('allowedmode','5g|3g|2g');
 | 
			
		||||
		o.depends('allowedmode','5g|4g');
 | 
			
		||||
		o.depends('allowedmode','5g|4g|2g');
 | 
			
		||||
		o.depends('allowedmode','5g|4g|3g');
 | 
			
		||||
		o.depends('allowedmode','5g|4g|3g|2g');
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'username', _('PAP/CHAP username'));
 | 
			
		||||
		o.depends('auth', 'pap');
 | 
			
		||||
		o.depends('auth', 'chap');
 | 
			
		||||
		o.depends('auth', 'both');
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'password', _('PAP/CHAP password'));
 | 
			
		||||
		o.depends('auth', 'pap');
 | 
			
		||||
		o.depends('auth', 'chap');
 | 
			
		||||
		o.depends('auth', 'both');
 | 
			
		||||
		o.password = true;
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.ListValue, 'iptype', _('IP Type'));
 | 
			
		||||
		o.value('ipv4v6', _('IPv4/IPv6 (both - defaults to IPv4)'))
 | 
			
		||||
		o.value('ipv4', _('IPv4 only'));
 | 
			
		||||
		o.value('ipv6', _('IPv6 only'));
 | 
			
		||||
		o.default = 'ipv4v6';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('advanced', form.Value, 'mtu', _('Override MTU'));
 | 
			
		||||
		o.placeholder = dev ? (dev.getMTU() || '1500') : '1500';
 | 
			
		||||
		o.datatype    = 'max(9200)';
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('general', form.Value, 'signalrate', _('Signal Refresh Rate'), _("In seconds"));
 | 
			
		||||
		o.datatype = 'uinteger';
 | 
			
		||||
		
 | 
			
		||||
		s.taboption('general', form.Value, 'metric', _('Gateway metric'));
 | 
			
		||||
		
 | 
			
		||||
		s.taboption('advanced', form.Flag, 'debugmode', _('Enable Debugmode'));
 | 
			
		||||
 | 
			
		||||
		o = s.taboption('advanced', form.ListValue, 'loglevel', _('Log output level'));
 | 
			
		||||
		o.value('ERR', _('Error'))
 | 
			
		||||
		o.value('WARN', _('Warning'));
 | 
			
		||||
		o.value('INFO', _('Info'));
 | 
			
		||||
		o.value('DEBUG', _('Debug'));
 | 
			
		||||
		o.default = 'ERR';
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,181 @@
 | 
			
		|||
'use strict';
 | 
			
		||||
'require ui';
 | 
			
		||||
'require view';
 | 
			
		||||
'require poll';
 | 
			
		||||
'require dom';
 | 
			
		||||
'require modemmanager_helper as helper';
 | 
			
		||||
 | 
			
		||||
return view.extend({
 | 
			
		||||
	load: function() {
 | 
			
		||||
		return helper.getModems().then(function (modems) {
 | 
			
		||||
			return Promise.all(modems.filter(function (modem){
 | 
			
		||||
				return modem != null;
 | 
			
		||||
			}).map(function (modem) {
 | 
			
		||||
				return helper.getModemSims(modem.modem).then(function (sims) {
 | 
			
		||||
					modem.sims = sims.filter(function (sim) {
 | 
			
		||||
						return sim != null;
 | 
			
		||||
					});
 | 
			
		||||
 | 
			
		||||
					return helper.getModemLocation(modem.modem).then(function (location) {
 | 
			
		||||
						modem.location = location;
 | 
			
		||||
						return modem;
 | 
			
		||||
					});
 | 
			
		||||
				});
 | 
			
		||||
			}));
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	pollData: function (container) {
 | 
			
		||||
		poll.add(L.bind(function () {
 | 
			
		||||
			return this.load().then(L.bind(function (modems) {
 | 
			
		||||
				dom.content(container, this.renderContent(modems));
 | 
			
		||||
			}, this));
 | 
			
		||||
		}, this));
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	renderSections: function (name, sections) {
 | 
			
		||||
		if (sections.length == 0) {
 | 
			
		||||
			sections.push(E('div', { 'class': 'cbi-section' }, [
 | 
			
		||||
				E('span', {}, _('Section %s is empty.').format(name))
 | 
			
		||||
			]));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return E('div', { 'class': 'cbi-section' }, [
 | 
			
		||||
			E('h1', {}, name),
 | 
			
		||||
			...sections
 | 
			
		||||
		]);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	renderSection: function (name, table) {
 | 
			
		||||
		var rowNodes = table.filter(function (row) {
 | 
			
		||||
			return row[1] != null;
 | 
			
		||||
		}).map(function (row) {
 | 
			
		||||
			return E('tr', { 'class': 'tr' }, [
 | 
			
		||||
				E('td', { 'class': 'td', 'width': '33%' }, E('strong', {}, [row[0]])),
 | 
			
		||||
				E('td', { 'class': 'td' }, [row[1]])
 | 
			
		||||
			]);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		var tableNode;
 | 
			
		||||
		if (rowNodes.length == 0) {
 | 
			
		||||
			tableNode = E('div', { 'class': 'cbi-section' }, [
 | 
			
		||||
				E('span', {}, _('Section %s is empty.').format(name))
 | 
			
		||||
			])
 | 
			
		||||
		} else {
 | 
			
		||||
			tableNode = E('table', { 'class': 'table', }, rowNodes);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return E('div', { 'class': 'cbi-section' }, [
 | 
			
		||||
			E('h2', {}, [name]),
 | 
			
		||||
			tableNode
 | 
			
		||||
		]);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	renderContent: function (modems) {
 | 
			
		||||
		var node = E('div', {}, E('div'));
 | 
			
		||||
 | 
			
		||||
		modems.forEach(L.bind(function (modem) {
 | 
			
		||||
			var generic = modem.modem.generic;
 | 
			
		||||
			var modem3gpp = modem.modem['3gpp'];
 | 
			
		||||
 | 
			
		||||
			var modemSection = this.renderSection(_('Modem Info'), [
 | 
			
		||||
				[_('Manufacturer'), generic.manufacturer],
 | 
			
		||||
				[_('Model'), generic.model],
 | 
			
		||||
				[_('Revision'), generic.revision],
 | 
			
		||||
				[E('abbr', { 'title': _('International Mobile Station Equipment Identity') }, [
 | 
			
		||||
					_('IMEI')
 | 
			
		||||
				]), modem3gpp.imei],
 | 
			
		||||
				[_('Device Identifier'), generic['device-identifier']],
 | 
			
		||||
				[_('Power State'), generic['power-state']],
 | 
			
		||||
				[_('State'), generic.state],
 | 
			
		||||
				[_('Failed Reason'), generic['state-failed-reason']]
 | 
			
		||||
			]);
 | 
			
		||||
 | 
			
		||||
			var ownNumbersStr = generic['own-numbers'].join(', ');
 | 
			
		||||
			var accessTechnologiesStr = generic['access-technologies'].join(', ');
 | 
			
		||||
			var signalQualityValue = parseInt(generic['signal-quality'].value);
 | 
			
		||||
			var networkSection = this.renderSection(_('Network Registration'), [
 | 
			
		||||
				[_('Own Numbers'), ownNumbersStr],
 | 
			
		||||
				[_('Access Technologies'), accessTechnologiesStr],
 | 
			
		||||
				[_('Operator') , modem3gpp['operator-name']],
 | 
			
		||||
				[_('Operator Code'), modem3gpp['operator-code']],
 | 
			
		||||
				[_('Registration State'), modem3gpp['registration-state']],
 | 
			
		||||
				[_('Packet Service State'), modem3gpp['packet-service-state']],
 | 
			
		||||
				[_('Signal Quality'), E('div', { 'class': 'cbi-progressbar', 'title': '%d %'.format(signalQualityValue) }, [
 | 
			
		||||
					E('div', { 'style': 'width: %d%%'.format(signalQualityValue) })
 | 
			
		||||
				])]
 | 
			
		||||
			]);
 | 
			
		||||
 | 
			
		||||
			var location3gpp = {};
 | 
			
		||||
			if (modem.location != null) {
 | 
			
		||||
				location3gpp = modem.location.modem.location['3gpp'];
 | 
			
		||||
			}
 | 
			
		||||
			var locationSection = this.renderSection(_('Cell Location'), [
 | 
			
		||||
				[E('abbr', { 'title': _('Cell ID') }, [
 | 
			
		||||
					'CID'
 | 
			
		||||
				]), location3gpp.cid],
 | 
			
		||||
				[E('abbr', { 'title': _('Location Area Code') }, [
 | 
			
		||||
					'LAC'
 | 
			
		||||
				]), location3gpp.lac],
 | 
			
		||||
				[E('abbr', { 'title': _('Mobile Country Code') }, [
 | 
			
		||||
					'MCC'
 | 
			
		||||
				]), location3gpp.mcc],
 | 
			
		||||
				[E('abbr', { 'title': _('Mobile Network Code') }, [
 | 
			
		||||
					'MNC'
 | 
			
		||||
				]), location3gpp.mnc],
 | 
			
		||||
				[E('abbr', { 'title': _('Tracking Area Code') }, [
 | 
			
		||||
					'TAC'
 | 
			
		||||
				]), location3gpp.tac]
 | 
			
		||||
			]);
 | 
			
		||||
 | 
			
		||||
			var simTables = modem.sims.map(function (sim) {
 | 
			
		||||
				var properties = sim.sim.properties;
 | 
			
		||||
				return [
 | 
			
		||||
					[_('Active'), properties.active],
 | 
			
		||||
					[_('Operator Name'), properties['operator-name']],
 | 
			
		||||
					[E('abbr', { 'title': _('Integrated Circuit Card Identifier') }, [
 | 
			
		||||
						'ICCID'
 | 
			
		||||
					]), properties.iccid],
 | 
			
		||||
					[E('abbr', { 'title': _('International Mobile Subscriber Identity') }, [
 | 
			
		||||
							'IMSI'
 | 
			
		||||
					]), properties.imsi]
 | 
			
		||||
				];
 | 
			
		||||
			});
 | 
			
		||||
			var simSubSections = simTables.map(L.bind(function (table, index) {
 | 
			
		||||
				return this.renderSection(_('SIM %d').format(index + 1), table)
 | 
			
		||||
			}, this));
 | 
			
		||||
			var simSection = this.renderSections(_('SIMs'), simSubSections);
 | 
			
		||||
 | 
			
		||||
			var sections = [
 | 
			
		||||
				E('div', { 'class': 'cbi-map-descr'}, []),
 | 
			
		||||
				modemSection,
 | 
			
		||||
				networkSection,
 | 
			
		||||
				locationSection,
 | 
			
		||||
				simSection
 | 
			
		||||
			].filter(function (section) {
 | 
			
		||||
				return section != null;
 | 
			
		||||
			});
 | 
			
		||||
			node.firstElementChild.appendChild(E('div', { 'data-tab': generic.device, 'data-tab-title': generic.device }, sections));
 | 
			
		||||
		}, this));
 | 
			
		||||
		ui.tabs.initTabGroup(node.firstElementChild.childNodes);
 | 
			
		||||
 | 
			
		||||
		return node;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	render: function (modems) {
 | 
			
		||||
		var content = E([], [
 | 
			
		||||
			E('h2', {}, [_('Cellular Network')]),
 | 
			
		||||
			E('div')
 | 
			
		||||
		]);
 | 
			
		||||
		var container = content.lastElementChild;
 | 
			
		||||
 | 
			
		||||
		dom.content(container, this.renderContent(modems));
 | 
			
		||||
		this.pollData(container);
 | 
			
		||||
 | 
			
		||||
		return content;
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	handleSaveApply: null,
 | 
			
		||||
	handleSave: null,
 | 
			
		||||
	handleReset: null
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
{
 | 
			
		||||
	"admin/status/modemmanager": {
 | 
			
		||||
		"title": "Cellular Network",
 | 
			
		||||
		"order": 10,
 | 
			
		||||
		"action": {
 | 
			
		||||
			"type": "view",
 | 
			
		||||
			"path": "modemmanager/status"
 | 
			
		||||
		},
 | 
			
		||||
		"depends": {
 | 
			
		||||
			"acl": [ "luci-proto-modemmanager" ]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
{
 | 
			
		||||
	"luci-proto-modemmanager": {
 | 
			
		||||
		"description": "Grant access to mmcli",
 | 
			
		||||
		"read": {
 | 
			
		||||
			"cgi-io": [ "exec" ],
 | 
			
		||||
			"file": {
 | 
			
		||||
				"/usr/bin/mmcli -L -J": [ "exec" ],
 | 
			
		||||
				"/usr/bin/mmcli -m [0-9]* -J": [ "exec" ],
 | 
			
		||||
				"/usr/bin/mmcli -i [0-9]* -J": [ "exec" ],
 | 
			
		||||
				"/usr/bin/mmcli -m [0-9]* --location-get -J": [ "exec" ]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue