UNPKG

iobroker.fb-checkpresence

Version:

The adapter checks the presence of family members over the fritzbox. You must fill in the name of the family member and the mac-address of the used device. The comment is optional and you can enable or disable the family member. The datapoint based on the

1,392 lines (1,373 loc) 71.4 kB
'use strict'; //Helper function //Exceptions /** * @param {string} name exception name * @param {string} message exception message */ function exceptionObjects(name, message) { this.name = name; this.message = message; this.toString = function () { return `${this.name}: ${this.message}`; }; } /** * @param {string} name exception name * @param {string} message exception message */ function infoObjects(name, message) { this.name = name; this.message = message; this.toString = function () { return `${this.name}: ${this.message}`; }; } function errorHandler(adapter, error, title) { if (typeof error === 'string') { adapter.log.warn(title); //adapter.log.warn(title + error.name + ' ' + error.message); } else if (typeof error === 'object') { if (error instanceof exceptionObjects) { adapter.log.warn(`${title} ${error.name} ${error.message}`); } else { if (error instanceof infoObjects) { adapter.log.info(`${title} ${error.name} ${error.message}`); } else { adapter.log.warn(`${title} ${error.name} ${error.message}`); } } } } function _common(type, opt, i) { const c = {}; if (type == 'state' || type == 'channel' || type == 'device' || type == 'folder') { c.name = opt[i][2]; c.desc = opt[i][8]; } if (type == 'state' || type == 'channel') { c.role = opt[i][4]; } if (type == 'state') { c.type = opt[i][3]; c.def = opt[i][5]; c.read = opt[i][6]; c.write = opt[i][7]; if (opt[i][9] != 'undefinded') { c.unit = opt[i][9]; } } if (type == 'device' || type == 'folder') { if (opt[i][10] != 'undefinded') { c.icon = opt[i][10]; } } return c; } //Helper function for creating and upating objects async function _createObjects(message, that, opt, enabled, adapterStates, memberStates) { try { for (let i = 0; i < opt.length; i++) { if (enabled === false) { break; } const id = opt[i][0]; const type = opt[i][1]; const c = _common(type, opt, i); const obj = await that.getObjectAsync(id); if (obj) { if (enabled === false) { break; } const objExt = await that.extendObjectAsync(id, { type: type, common: c, native: {} }); if (!objExt) { throw new exceptionObjects('exceptionCouldNotExtendObj', `Could not extend object with id <${id}>`); } } else { if (enabled === false) { break; } const objNotExist = await that.setObjectNotExistsAsync(id, { type: type, common: c, native: {} }); if (!objNotExist) { throw new exceptionObjects('exceptionCouldNotCreateObj', `Could not create object with id <${id}>`); } } if (type == 'state') { if (enabled === false) { break; } const state = await that.getStateAsync(id); if (state && state.val === null) { //that.setState(id, c.def, true); //set default state.val = c.def; } if (adapterStates) { const ind = that.adapterStates.findIndex(x => x.id == id); if (ind == -1) { adapterStates.push({ id: id, state: state }); } if (ind >= 0) { adapterStates[ind].state.val = state.val; } } //if (memberStates && id.includes('.presence')) memberStates.push(JSON.parse(JSON.stringify({id: id, state: state}))); if (memberStates && id.includes('.presence')) { memberStates.push({ ...{ id: id, state: state } }); } } } return true; } catch (error) { errorHandler(that, error, 'createObjects: '); return false; } } async function _enableHistory(that, cfg, group, familyMember, historyAlive) { try { let alias = ''; const member = familyMember; //const memberPath = group + member; let id = null; if (group == '' && that.config.compatibility === true) { id = group == '' ? member : `${group + member}.presence`; } if (group == '' && that.config.compatibility === false) { id = `familyMembers.${member}.presence`; } if (group != '') { id = `${group + member}.presence`; } if (historyAlive === true) { const result = await that.sendToAsync(cfg.history, 'getEnabledDPs', {}); if ( result[`${that.namespace}` + `.${id}`] != undefined && result[`${that.namespace}` + `.${id}`].aliasId != undefined ) { alias = result[`${that.namespace}` + `.${id}`].aliasId; } if ( result[`${that.namespace}` + `.${id}`] != undefined && result[`${that.namespace}` + `.${id}`].enabled == true ) { return true; } const result2 = await that.sendToAsync(cfg.history, 'enableHistory', { id: `${that.namespace}` + `.${id}`, options: { changesOnly: true, debounce: 0, retention: 31536000, changesRelogInterval: 0, maxLength: 10, changesMinDelta: 0, aliasId: alias, }, }); if (result2.error) { return false; } if (result2.success) { that.log.debug(`enableHistory.2 ${member} ${result2.success}`); return true; } } } catch (error) { errorHandler(that, error, 'enableHistory: '); return false; } } /** * * @param that - adapter object * @param adapterStates - adapter object states * @param table - html table * @param tableGuest - html table guest members * @param enabled - function enabled */ async function createGlobalObjects(that, adapterStates, table, tableGuest, enabled) { try { const optGeneral = [ // Legende: o - optional //id, type, common.name (o), common.type (o), common.role, common.def (o), common.rd, common.wr, common.desc (o) //common.type (possible values: number, string, boolean, array, object, mixed, file) //info objects, states [ 'info.connection', 'state', 'info.connection', 'boolean', 'indicator.connected', false, true, false, 'Fritzbox connection state', ], [ 'info.X_AVM-DE_GetHostListPath', 'state', 'info.X_AVM-DE_GetHostListPath', 'boolean', 'indicator', false, true, false, 'Fritzbox service X_AVM-DE_GetHostListPath available', ], [ 'info.X_AVM-DE_GetMeshListPath', 'state', 'info.X_AVM-DE_GetMeshListPath', 'boolean', 'indicator', false, true, false, 'Fritzbox service X_AVM-DE_GetMeshListPath available', ], [ 'info.GetSpecificHostEntry', 'state', 'info.GetSpecificHostEntry', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetSpecificHostEntry available', ], [ 'info.X_AVM-DE_GetSpecificHostEntryByIP', 'state', 'info.X_AVM-DE_GetSpecificHostEntryByIP', 'boolean', 'indicator', false, true, false, 'Fritzbox service X_AVM-DE_GetSpecificHostEntryByIP available', ], [ 'info.GetSecurityPort', 'state', 'info.GetSecurityPort', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetSecurityPort available', ], [ 'info.GetInfo', 'state', 'info.GetInfo', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetInfo available', ], [ 'info.SetEnable', 'state', 'info.SetEnable', 'boolean', 'indicator', false, true, false, 'Fritzbox service SetEnable available', ], [ 'info.WLANConfiguration3-GetInfo', 'state', 'info.WLANConfiguration3-GetInfo', 'boolean', 'indicator', false, true, false, 'Fritzbox service WLANConfiguration3-GetInfo available', ], [ 'info.WLANConfiguration3-GetSecurityKeys', 'state', 'info.GetSecurityKeys', 'boolean', 'indicator', false, true, false, 'Fritzbox service WLANConfiguration3-GetSecurityKeys available', ], [ 'info.ForceTermination', 'state', 'info.ForceTermination', 'boolean', 'indicator', false, true, false, 'Fritzbox service ForceTermination available', ], [ 'info.GetCommonLinkProperties', 'state', 'info.GetCommonLinkProperties', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetCommonLinkProperties available', ], [ 'info.X_AVM-DE_GetCurrentUser', 'state', 'info.X_AVM-DE_GetCurrentUser', 'boolean', 'indicator', false, true, false, 'Fritzbox service X_AVM-DE_GetCurrentUser available', ], [ 'info.DisallowWANAccessByIP', 'state', 'info.DisallowWANAccessByIP', 'boolean', 'indicator', false, true, false, 'Fritzbox service DisallowWANAccessByIP available', ], [ 'info.GetWANAccessByIP', 'state', 'info.GetWANAccessByIP', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetWANAccessByIP available', ], [ 'info.Reboot', 'state', 'info.Reboot', 'boolean', 'indicator', false, true, false, 'Fritzbox service Reboot available', ], [ 'info.DeviceInfo1-GetInfo', 'state', 'info.DeviceInfo1-GetInfo', 'boolean', 'indicator', false, true, false, 'Fritzbox service DeviceInfo1-GetInfo available', ], [ 'info.GetDefaultConnectionService', 'state', 'info.GetDefaultConnectionService', 'boolean', 'indicator', false, true, false, 'Fritzbox service GetDefaultConnectionService available', ], [ 'info.lastUpdate', 'state', 'lastUpdate', 'string', 'date', new Date('1900-01-01T00:00:00').toString(), true, false, 'last connection datetime', ], //general states ['reconnect', 'state', 'reconnect', 'boolean', 'button', false, true, true, 'Reconnect Fritzbox'], ['reboot', 'state', 'reboot', 'boolean', 'button', false, true, true, 'Reboot Fritzbox'], ]; let optExtIp = []; optExtIp = [ ['info.extIp', 'state', 'info.extIp', 'string', 'value', '', true, false, 'external ip address'], ['info.extIpv6', 'state', 'info.extIpv6', 'string', 'value', '', true, false, 'external ipv6 address'], ['info.extIpv6Prf', 'state', 'info.extIpv6Prf', 'string', 'value', '', true, false, 'external ipv6 prefix'], ]; let optGuest = []; if (that.config.compatibility === true) { optGuest = [ //guest objects, states ['guest', 'state', 'guest', 'boolean', 'indicator', false, true, false, 'Guest is logged in'], ['guest.count', 'state', 'count', 'number', 'value', 0, true, false, 'Number of guests'], ['guest.presentGuests', 'state', 'presentGuests', 'string', 'value', '', true, false, 'Guests present'], ['guest.listJson', 'state', 'listJson', 'string', 'json', '[]', true, false, 'Guest list json'], ['guest.listHtml', 'state', 'listHtml', 'string', 'html', tableGuest, true, false, 'Guest list html'], [ 'guest.presence', 'state', 'guest.presence', 'boolean', 'indicator', false, true, false, 'a guest is present', ], [ 'guest.wlan', 'state', 'guest.wlan', 'boolean', 'indicator', false, true, true, 'guest wlan is on or off', ], ]; } else { optGuest = [ //guest objects, states ['guest', 'folder', 'guest', '', '', '', true, false, 'Guest is logged in'], ['guest.count', 'state', 'count', 'number', 'value', 0, true, false, 'Number of guests'], ['guest.presentGuests', 'state', 'presentGuests', 'string', 'value', '', true, false, 'Guests present'], ['guest.listJson', 'state', 'listJson', 'string', 'json', '[]', true, false, 'Guest list json'], ['guest.listHtml', 'state', 'listHtml', 'string', 'html', tableGuest, true, false, 'Guest list html'], [ 'guest.presence', 'state', 'guest.presence', 'boolean', 'indicator', false, true, false, 'a guest is present', ], [ 'guest.wlan', 'state', 'guest.wlan', 'boolean', 'indicator', false, true, true, 'guest wlan is on or off', ], ]; } const optQR = [ ['guest.wlanQR', 'state', 'guest.wlanQR', 'string', 'value', '', true, true, 'guest wlan QR code'], ]; let optDev = [ //fb-devices objects, states ['fb-devices', 'folder', 'fb-devices', '', '', '', true, false, 'folder for fritzbox devices'], [ 'fb-devices.count', 'state', 'fb-devices.count', 'number', 'value', 0, true, false, 'Number of fritzbox devices', ], [ 'fb-devices.active', 'state', 'fb-devices.active', 'number', 'value', 0, true, false, 'Number of active devices', ], [ 'fb-devices.inactive', 'state', 'fb-devices.inactive', 'number', 'value', 0, true, false, 'Number of inactive devices', ], [ 'fb-devices.json', 'state', 'fb-devices.json', 'string', 'json', '[]', true, false, 'fritzbox device list json', ], [ 'fb-devices.mesh', 'state', 'fb-devices.mesh', 'string', 'json', '[]', true, false, 'fritzbox mesh list json', ], [ 'fb-devices.jsonActive', 'state', 'fb-devices.jsonActive', 'string', 'json', '[]', true, false, 'fritzbox active device list json', ], [ 'fb-devices.jsonInactive', 'state', 'fb-devices.jsonInactive', 'string', 'json', '[]', true, false, 'fritzbox inactive device list json', ], [ 'fb-devices.html', 'state', 'fb-devices.html', 'string', 'html', '', true, false, 'fritzbox device list html', ], [ 'fb-devices.jsonActiveVPN', 'state', 'fb-devices.jsonActiveVPN', 'string', 'json', '[]', true, false, 'fritzbox active vpn device list json', ], ]; if (that.config.compatibility === true) { //only for compatibility const optDev2 = [ ['devices', 'state', 'devices', 'number', 'value', 0, true, false, 'Number of devices'], [ 'activeDevices', 'state', 'activeDevices', 'number', 'value', 0, true, false, 'Number of active devices', ], ]; optDev = optDev.concat(optDev2); } let optWlBl = []; if (that.config.compatibility === true) { optWlBl = [ //blacklist objects, states ['blacklist', 'state', 'blacklist', 'boolean', 'indicator', false, true, false, 'Unknown devices'], ['blacklist.count', 'state', 'count', 'number', 'value', 0, true, false, 'Number of unknown devices'], [ 'blacklist.presence', 'state', 'blacklist.presence', 'boolean', 'indicator', false, true, false, 'a device is not listed in the whitelist and is active', ], [ 'blacklist.listJson', 'state', 'listJson', 'string', 'json', '[]', true, false, 'Unknown devices list json', ], [ 'blacklist.listHtml', 'state', 'listHtml', 'string', 'html', tableGuest, true, false, 'Unknown devices list html', ], //whitelist objects, states ['whitelist', 'folder', 'whitelist', '', '', '', true, false, 'whitelist'], [ 'whitelist.count', 'state', 'whitelist.count', 'number', 'value', 0, true, false, 'Number of whitelist devices', ], [ 'whitelist.json', 'state', 'whitelist.json', 'string', 'json', '[]', true, false, 'whitelist devices json', ], [ 'whitelist.html', 'state', 'whitelist.html', 'string', 'html', tableGuest, true, false, 'whitelist devices html', ], ]; } else { optWlBl = [ //blacklist objects, states ['blacklist', 'folder', 'blacklist', '', '', '', true, false, 'Unknown devices'], ['blacklist.count', 'state', 'count', 'number', 'value', 0, true, false, 'Number of unknown devices'], [ 'blacklist.presence', 'state', 'blacklist.presence', 'boolean', 'indicator', false, true, false, 'a device is not listed in the whitelist and is active', ], [ 'blacklist.listJson', 'state', 'listJson', 'string', 'json', '[]', true, false, 'Unknown devices list json', ], [ 'blacklist.listHtml', 'state', 'listHtml', 'string', 'html', tableGuest, true, false, 'Unknown devices list html', ], //whitelist objects, states ['whitelist', 'folder', 'whitelist', '', '', '', true, false, 'whitelist'], [ 'whitelist.count', 'state', 'whitelist.count', 'number', 'value', 0, true, false, 'Number of whitelist devices', ], [ 'whitelist.json', 'state', 'whitelist.json', 'string', 'json', '[]', true, false, 'whitelist devices json', ], [ 'whitelist.html', 'state', 'whitelist.html', 'string', 'html', tableGuest, true, false, 'whitelist devices html', ], ]; } let opt = optGeneral; if (that.config.enableWl == true) { opt = opt.concat(optWlBl); } if (that.config.fbdevices == true) { opt = opt.concat(optDev); } if (that.config.guestinfo == true) { opt = opt.concat(optGuest); } if (that.config.qrcode == true) { opt = opt.concat(optQR); } if (that.config.extip === true) { opt = opt.concat(optExtIp); } if (that.config.compatibility == true) { that.log.warn( 'The state "guest" will not longer exist in a future version. Please use "guest.presence" instead!', ); that.log.warn( 'The state "blacklist" will not longer exist in a future version. Please use "blacklist.presence" instead!', ); that.log.warn( 'The state "activeDevices" will not longer exist in a future version. Please use "fb-devices.active" instead!', ); that.log.warn( 'The state "devices" will not longer exist in a future version. Please use "fb-devices.count" instead!', ); } await _createObjects('createGlobalObjects', that, opt, enabled, adapterStates, null); that.log.info('createGlobalObjects finished successfully'); return true; } catch (error) { errorHandler(that, error, 'createGlobalObjects: '); return false; } } /** * * @param that - adapter object * @param membersFiltered - list of only active family members * @param familyGroups - list of member groups * @param adapterStates - list of adapter states * @param memberStates - list of member states * @param cfg - adapter configuration * @param table - html history table * @param enabled - function is enabled * @param historyAlive - history adapter is alive */ async function createMemberObjects( that, membersFiltered, familyGroups, adapterStates, memberStates, cfg, table, enabled, historyAlive, ) { try { if (membersFiltered == undefined || membersFiltered.length == 0) { throw new infoObjects('infoNoFamilyMembers', 'no family members defined! Objects are not created!'); } else { //Create objects for family members for (let g = 0; g < familyGroups.length; g++) { const group = familyGroups[g]; let opt = []; if (group == '' && that.config.compatibility === true) { opt = [ //general family member states [ 'familyMembers', 'folder', 'familyMembers', '', '', '', true, false, 'folder for family groups', ], [ 'presence', 'state', 'presence', 'boolean', 'indicator', false, true, false, 'someone from the family are present', ], [ 'presenceAll', 'state', 'presenceAll', 'boolean', 'indicator', false, true, false, 'All of the family are present', ], [ 'absence', 'state', 'absence', 'boolean', 'indicator', false, true, false, 'someone from the family are absent', ], [ 'absenceAll', 'state', 'absenceAll', 'boolean', 'indicator', false, true, false, 'All of the family are absent', ], [ 'presentMembers', 'state', 'presentMembers', 'string', 'value', '', true, false, 'who is present', ], [ 'absentMembers', 'state', 'absentMembers', 'string', 'value', '', true, false, 'who is absent', ], ['presentCount', 'state', 'presentCount', 'number', 'value', 0, true, false, 'who is present'], ['absentCount', 'state', 'absentCount', 'number', 'value', 0, true, false, 'who is absent'], ['json', 'state', 'json', 'string', 'json', '[]', true, false, 'Json table'], ['html', 'state', 'html', 'string', 'html', table, true, false, 'Html table'], ]; } //general group states if (group == '' && that.config.compatibility === false) { opt = [ [ 'familyMembers', 'folder', 'familyMembers', '', '', '', true, false, 'folder for family groups', ], [ 'familyMembers' + '.presence', 'state', 'familyMembers' + '.presence', 'boolean', 'indicator', false, true, false, 'someone from the family are present', ], [ 'familyMembers' + '.presenceAll', 'state', 'familyMembers' + '.presenceAll', 'boolean', 'indicator', false, true, false, 'All of the family are present', ], [ 'familyMembers' + '.absence', 'state', 'familyMembers' + '.absence', 'boolean', 'indicator', false, true, false, 'someone from the family are absent', ], [ 'familyMembers' + '.absenceAll', 'state', 'familyMembers' + '.absenceAll', 'boolean', 'indicator', false, true, false, 'All of the family are absent', ], [ 'familyMembers' + '.presentMembers', 'state', 'familyMembers' + '.presentMembers', 'string', 'value', '', true, false, 'who is present', ], [ 'familyMembers' + '.absentMembers', 'state', 'familyMembers' + '.absentMembers', 'string', 'value', '', true, false, 'who is absent', ], [ 'familyMembers' + '.presentCount', 'state', 'familyMembers' + '.presentCount', 'number', 'value', 0, true, false, 'who is present', ], [ 'familyMembers' + '.absentCount', 'state', 'familyMembers' + '.absentCount', 'number', 'value', 0, true, false, 'who is absent', ], [ 'familyMembers' + '.json', 'state', 'familyMembers' + '.json', 'string', 'json', '[]', true, false, 'Json table', ], [ 'familyMembers' + '.html', 'state', 'familyMembers' + '.html', 'string', 'html', table, true, false, 'Html table', ], ]; } if (group != '') { opt = [ [ 'familyMembers', 'folder', 'familyMembers', '', '', '', true, false, 'folder for family groups', ], [ `familyMembers.${group}`, 'folder', `familyMembers.${group}`, '', '', '', true, false, 'folder for family group', ], [ `familyMembers.${group}.presence`, 'state', `familyMembers.${group}.presence`, 'boolean', 'indicator', false, true, false, 'someone from the family are present', ], [ `familyMembers.${group}.presenceAll`, 'state', `familyMembers.${group}.presenceAll`, 'boolean', 'indicator', false, true, false, 'All of the family are present', ], [ `familyMembers.${group}.absence`, 'state', `familyMembers.${group}.absence`, 'boolean', 'indicator', false, true, false, 'someone from the family are absent', ], [ `familyMembers.${group}.absenceAll`, 'state', `familyMembers.${group}.absenceAll`, 'boolean', 'indicator', false, true, false, 'All of the family are absent', ], [ `familyMembers.${group}.presentMembers`, 'state', `familyMembers.${group}.presentMembers`, 'string', 'value', '', true, false, 'who is present', ], [ `familyMembers.${group}.absentMembers`, 'state', `familyMembers.${group}.absentMembers`, 'string', 'value', '', true, false, 'who is absent', ], [ `familyMembers.${group}.presentCount`, 'state', `familyMembers.${group}.presentCount`, 'number', 'value', 0, true, false, 'who is present', ], [ `familyMembers.${group}.absentCount`, 'state', `familyMembers.${group}.absentCount`, 'number', 'value', 0, true, false, 'who is absent', ], [ `familyMembers.${group}.json`, 'state', `familyMembers.${group}.json`, 'string', 'json', '[]', true, false, 'Json table', ], [ `familyMembers.${group}.html`, 'state', `familyMembers.${group}.html`, 'string', 'html', table, true, false, 'Html table', ], ]; } await _createObjects('createMemberObjects', that, opt, enabled, adapterStates); } //Create objects for family members for (let k = 0; k < membersFiltered.length; k++) { const memberRow = membersFiltered[k]; const member = memberRow.familymember; const group = memberRow.group == '' ? '' : `familyMembers.${memberRow.group}.`; let opt = []; if (group == '' && that.config.compatibility === true) { opt = [ [ group + member, 'state', 'member', 'boolean', 'indicator', false, true, false, 'Family member', ], [ `${group + member}.presence`, 'state', `${member}.presence`, 'boolean', 'indicator', false, true, false, 'state of the family member', ], [ `${group + member}.history`, 'state', 'history', 'string', 'json', '[]', true, false, 'history of the day as json table', ], [ `${group + member}.historyHtml`, 'state', 'historyHtml', 'string', 'html', table, true, false, 'history of the day as html table', ], [ `${group + member}.going`, 'state', 'going', 'string', 'date', new Date().toString(), true, false, 'time when you leaving the home', ], [ `${group + member}.comming`, 'state', 'comming', 'string', 'date', new Date().toString(), true, false, 'time when you arriving at home', ], [ `${group + member}.speed`, 'state', `${member}.speed`, 'number', 'value', 0, true, false, 'Speed of the device', 'Mbit/s', ], [ `${group + member}.link`, 'state', `${member}.link`, 'string', 'value', '', true, false, 'Link of the device', '', ], [ `${group + member}.absent.since`, 'state', `${member}.absent.since`, 'number', 'value', 0, true, false, 'absent since', 'min', ], [ `${group + member}.present.since`, 'state', `${member}.present.since`, 'number', 'value', 0, true, false, 'present since', 'min', ], [ `${group + member}.absent.sum_day`, 'state', `${member}.absent.sum_day`, 'number', 'value', 0, true, false, 'how long absent per day', 'min', ], [ `${group + member}.present.sum_day`, 'state', `${member}.present.sum_day`, 'number', 'value', 0, true, false, 'how long present per day', 'min', ], ]; if (that.config.newfilter == true) { opt = opt.concat([ [ `${group + member}.presenceFiltered`, 'state', `${member}.presenceFiltered`, 'boolean', 'indicator', false, true, false, 'state of the family member', ], ]); } that.log.warn( `The state "` + `${that.namespace}` + `.${member}" will not longer exist in a future version. Please use ` + `${that.namespace}` + `.${member}.presence" instead!`, ); } if (group == '' && that.config.compatibility === false) { opt = [ [ `familyMembers.${group}${member}`, 'folder', group + member, '', '', '', true, false, 'Family member', ], [ `familyMembers.${group}${member}.presence`, 'state', `${member}.presence`, 'boolean', 'indicator', false, true, false, 'state of the family member', ], [ `familyMembers.${group}${member}.history`, 'state', 'history', 'string', 'json', '[]', true, false, 'history of the da