Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Entwicklung
  4. Adapter: fireTv

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    16
    1
    1.4k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    815

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.1k

Adapter: fireTv

Geplant Angeheftet Gesperrt Verschoben Entwicklung
firetvfiretv 4kadapterentwicklungadb
4 Beiträge 3 Kommentatoren 922 Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • H Offline
    H Offline
    HenryH
    schrieb am zuletzt editiert von
    #1

    Hi,

    hab den Adapter fireTV zum laufen gebracht, da das was ich brauche fehlt wollte ich es selbst erweitern.

    Ich hätte gerne zwei Infos, bei denen ich auch weiß wie ich die Abgreifen kann.

    • Aktuelle App
    • Wird gerade was wiedergegeben

    Hab den passenden ADB-Shell Befehl mal in "shell" gesendet, jedoch kommt nichts zurück.
    Dachte dann, ach mach ich halt den sauberen Weg und bau das in den Adapter als Datenpunkt, jedoch komme ich nicht weiter.

    Der Datenpunkt wird nicht befüllt, aber angelegt. Auch bekomme ich keine Logmeldungen.

    Hier meine angepasste firetv.js:

    "use strict";
    
    var soef = require(`${__dirname}/lib/dontBeSoSoef`),
        adb = require('adbkit'),
        path = require('path'),
        Mdns = require('mdns-discovery');
    
    let Client;
    try {
        Client = require('./node_modules/adbkit/lib/adb/client.js');
    } catch (e) {
        Client = require('../adbkit/lib/adb/client');
    }
    
    soef.extendAll();
    
    Client.prototype.shellEx = function(id, command, cb) {
        //this.parent.shell.call( this, id, command, function (err, stream) {
        this.shell(id, command, function (err, stream) {
            if (err || !stream) return cb & cb(err, 0);
            adb.util.readAll(stream, function (err, output) {
                if (err || !stream) return cb && cb(err);
                var ar = output.toString().split('\r\n');
                ar.length--;
                for (var i=ar.length-1; i > ar.length-10; i++) {
                    adapter.log.debug(ar[i]);
                }
                cb && cb(0, ar);
            });
        })
    };
    
    // Client.prototype.shell1 = function (id, command, cb) {
    //     return this.shellEx(id, command, function (err, ar) {
    //         cb && cb(err, (ar && ar.length) ? ar[0] : '');
    //     });
    // };
    
    Client.prototype.getIP = function(id, cb) {
        var self = this;
        this.getProperties(id, function (err, properties) {
            if (!err && properties) {
                var ip = soef.getProp(properties, "dhcp.eth0.ipaddress");
                ip = ip || soef.getProp(properties, "dhcp.wlan0.ipaddress");
                if (ip) return cb && cb(0, ip);
            }
            self.shellEx(id, "ifconfig wlan0", function (err, ar) {
                if (err || !ar) return cb && cb('');
                ar.forEach(function (line) {
                    var a = line.trim().split('  ');
                    if (a && a.length) {
                        a = a[0].split(':');
                        if (a && a.length && a[0] === 'inet addr') {
                            ip = a [1];
                            if (ip) return cb && cb(ip);
                        }
                    }
                });
                cb && cb('');
            });
        });
    };
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    var fireTVs = {};
    var g_client;
    var isWin = process.platform === 'win32';
    
    var knownAppPathes = {
        kodi:     'org.xbmc.kodi/.Splash',
        xbmc:     'org.xbmc.kodi/.Splash',
        netflix:  'com.netflix.ninja',
        tvnow:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
        nowtv:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
        zdf:      'com.zdf.android.mediathek',
        ard:      'com.daserste.daserste',
        daserste: 'com.daserste.daserste'
    };
    
    //am start -n com.netflix.ninja
    //am start -W -S -n com.netflix.ninja/.MainActivityam
    
    var adapter = soef.Adapter (
        main,
        onStateChange,
        onUnload,
        onMessage,
        'firetv'
    );
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    var usedStateNames = {
        online:             { n: 'online',      val: false, common: { write: false, min: false, max: true }},
        currentApp:         { n: 'currentApp',  val: '',    common: { write: false }},
        currentActivity:    { n: 'currentActivity', val: '',common: { write: false }},
        startApp:           { n: 'startApp',    val: '',    common: { desc: 'start an application e.g.: com.netflix.ninja/.MainActivity'}},
        stopApp:            { n: 'stopApp',     val: '',    common: { desc: 'stops an application e.g.: com.netflix.ninja'}},
        sendKeyCode:        { n: 'sendKeyCode', val: 0,     common: { }},
        sendKeyCodeArray:   { n: '',            val: '',    common: { desc: 'Can be an array of keys and delays. e.g.: 4000, DOWN, 100, DOWN, DOWN, LEFT, ENTER, 5000, LEFT' }},
        reboot:             { n: 'reboot',      val: false, common: { min: false, max: true}},
        screencap:          { n: 'screencap',   val: false, common: { min: false, max: true}},
        result:             { n: 'result',      val: '',    common: { write: false }},
        swapPower:          { n: 'swapPower',   val: false, common: { min: false, max: true}},
        on:                 { n: 'on',          val: false, common: { min: false, max: true}},
        state:              { n: 'state',       val: '',    common: { }},
        shell:              { n: 'shell',       val: '',    common: { desc: 'send an adb shell command'}},
        text:               { n: 'text',        val: '',    common: { desc: 'send "text" to the device'}},
        sendevent:          { n: 'sendevent',   val: '',    common: { } },
    
        //framebuffer:        { n: 'framebuffer', val: '',    common: { } },
    
        enter:              { n: 'keys.enter',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ENTER }},
        left:               { n: 'keys.left',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_LEFT }},
        right:              { n: 'keys.right',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_RIGHT }},
        up:                 { n: 'keys.up',     val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_UP }},
        down:               { n: 'keys.down',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_DOWN }},
        home:               { n: 'keys.home',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_HOME }},
        back:               { n: 'keys.back',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_BACK }},
        menu:               { n: 'keys.menu',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_MENU }},
        escape:             { n: 'keys.escape', val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ESCAPE}}
    };
    for (var i in usedStateNames) {
        var o = usedStateNames[i];
        if (!o.n) o.n = i;
    }
    
    
    function prepareStates() {
        var o = {};
        for (var i in adb.Keycode) {
            o[adb.Keycode[i]] = i.substr(8);
        }
        usedStateNames.sendKeyCode.common.states = o;
    }
    prepareStates();
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    function onStateChange(id, state) {
        var dcs = adapter.idToDCS(id);
        var ftv = fireTVs[dcs.device];
        if (ftv) {
            if (ftv.onStateChange(dcs.channel, dcs.state, state.val) === true) {
                ftv.dev.setImmediately(soef.ns.no(id), false);
            }
        }
    }
    
    
    function onMessage (obj) {
        if (!obj) return;
        switch (obj.command) {
            case 'discovery':
                var mdns = Mdns({
                    timeout: 3,
                    name: '_amzn-wplay._tcp.local',
                    find: 'amzn.dmgr:'
                });
                mdns.setFilter('ip', adapter.config.devices).run (function(res) {
                    if (obj.callback) {
                        res.forEach(function(v) {
                            v.enabled = true;
                        });
                        adapter.sendTo (obj.from, obj.command, JSON.stringify(res), obj.callback);
                    }
                });
                return true;
            default:
                adapter.log.warn("Unknown command: " + obj.command);
                break;
        }
        if (obj.callback) adapter.sendTo (obj.from, obj.command, obj.message, obj.callback);
        return true;
    }
    
    
    function closeAllFireTVs() {
        for (var i in fireTVs) {
            fireTVs[i].close();
            delete fireTVs[i];
        }
    
    }
    
    function onUnload(callback) {
        closeAllFireTVs();
        g_client.close();
        callback && callback();
    }
    
    function new_g_client() {
        if (g_client) return;
        g_client = adb.createClient({bin: adapter.config.adbPath});
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    function trackDevices() {
    
        function set(device, val) {
            if (!device || !device.id) return;
            var ar = device.id.split(':');
            var ftv = fireTVs[normalizedName(ar[0])];
            if (ftv) {
                ftv.setOnline(val);
                ftv.updatePowerState();
                ftv.updateCurrentApp();
                ftv.updateState();
            }
        }
        new_g_client();
        g_client.trackDevices()
            .then(function (tracker) {
                tracker.on('add', function (device) {
                    set(device, true);
                    adapter.log.debug('Device ' + device.id + ' + type=' + device.type + ' was plugged in');
                });
                tracker.on('remove', function (device) {
                    set(device, false);
                    adapter.log.debug('Device ' + device.id + ' was unplugged');
                });
                tracker.on('end', function () {
                    adapter.log.debug('Tracking stopped');
                });
            })
            .catch(function (err) {
                adapter.log.debug('Something went wrong:' + err.message)
            })
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    var FireTV = function (entry) {
        this.dev = new devices.CDevice(entry.ip, entry.name);
        this.id = entry.ip;
        adapter.log.debug("FireTV: " + entry.ip);
        var d = this.dev.getFullId('');
        fireTVs [d] = this;
    };
    
    
    FireTV.prototype.startClient = function(cb) {
        var self = this;
        this.client = adb.createClient({ bin: adapter.config.adbPath });
        this.client.connect(this.id, 5555, function(err, id) {
            if (err || !id) {
                adapter.log.error('can not connect to ' + self.id + ' Error=' + err.message);
                return;
            }
            self.client.id = id;
            self.client.getState(id, function(err,state) {
                adapter.log.debug('Connected to ' + self.id + ' id=' + id + ((!err && state) ? ' state=' + state : ""));
                self.updateState(state);
            });
    
            // self.client.getProperties(id, function(err, properties) {
            // });
            // self.client.getPackages(id, function(err, packages) {
            //     if (err || !packages) return;
            // });
    
            self.client.version(function(err, version) {
                self.getAndroidVersion(function(androidVersion) {
                    self.getAPILevel(function (apiLevel) {
                        soef.log("%s: ADB version: %s, Android Version: %s, API Level: %s", self.id, version, androidVersion, apiLevel);
                    });
                });
            });
            self.updatePowerState();
            self.updateCurrentApp();
        });
        cb && cb();
    };
    
    
    FireTV.prototype.createStates = function (cb) {
        for (var j in usedStateNames) {
            var st = Object.assign({}, usedStateNames[j]);
            this.dev.createNew(st.n, st);
        }
        devices.update(function() {
            this.startClient(cb);
        }.bind(this));
    };
    
    
    FireTV.prototype.close = function() {
        if (this.client && this.client.id) {
            this.client.disconnect(this.client.id).catch(function (err) {
                adapter.log.debug('Something went wrong:' + err.message)
            });
            this.client.kill(function(err) {
                 if (err) adapter.log('error killing adb server: ' + err.message);
            });
            this.client = undefined;
        }
    };
    
    FireTV.prototype.getAndroidVersion = function (cb) {
        return this.shell1('getprop ro.build.version.release', cb);
    };
    
    FireTV.prototype.getAPILevel = function (cb) {
        return this.shell1('getprop ro.build.version.sdk', cb);
    };
    
    FireTV.prototype.setOnline = function (online) {
        this.dev.setImmediately(usedStateNames.online.n, !!online);
    };
    
    
    FireTV.prototype.handleCallback = function (err, stream, cb) {
        if (err || !stream) {
            adapter.log.error('ID: ' + this.id + ' Error=' + err.message);
            if (err && err.message) this.dev.setImmediately('error', err.message);
            return cb && cb();
        }
        var self = this;
        adb.util.readAll(stream, function(err, output) {
            if (!err && output) {
                var ar = output.toString().split('\r\n');
                ar.length--;
                // for (var i = Math.max(0, ar.length-10); i < ar.length; i++) {
                //     var line = ar[i];
                //     adapter.log.debug(line);
                //     self.dev.setImmediately('result', line);
                // }
                if (ar.length < 10) ar.forEach(function (line) {
                    adapter.log.debug(line);
                    self.dev.setImmediately('result', line);
                });
            }
            if (cb) cb (ar);
        });
    };
    
    
    FireTV.prototype.shell1 /*Line*/ = function (cmd, cb) {
        this.shell (cmd, function(ar) {
            if (ar && ar.length) return cb && cb(ar[0]);
            cb && cb('');
        })
    };
    
    FireTV.prototype.shell = function (command, cb) {
        if (!this.client || !this.client.id) return cb && cb('client.id not set');
        this.client.shell(this.client.id, command, function(err, stream) {
            this.handleCallback(err, stream, cb);
        }.bind(this));
    };
    
    
    function lines2Object(lines) {
        var o = {};
        if (!lines) return o;
        if (typeof lines === 'string') lines = lines.split('\r\n');
        lines.forEach(function(line) {
            line = line.trim().replace(/ |:/g, '_');
            var ar = line.split('=');
             if (ar && ar.length >= 2) {
                 o [ar[0]] = valtype(ar[1]);
             }
        });
        return o;
    }
    
    
    FireTV.prototype.updatePowerState = function (cb) {
        this.getPowerState(function (on) {
            this.dev.setImmediately(usedStateNames.on.n, on);
            cb && cb(on);
        }.bind(this));
    };
    FireTV.prototype.updateCurrentApp = function (cb) {
        this.getCurrentApp(function (currentApp) {
            this.dev.setImmediately(usedStateNames.currentApp.n, currentApp);
            cb && cb(currentApp);
        }.bind(this));
    };
    FireTV.prototype.updateState = function (state) {
        this.dev.setImmediately(usedStateNames.state.n, state);
    };
    
    
    FireTV.prototype.getPowerState = function (cb) {
        this.shell('dumpsys power', function (ar) {
            // var value = ar.join('\r');
            // var RE_KEYVAL = /^\s*(\S*)=(\S)\r?$/gm;
            // var properties = {};
            // var match;
            // value = value.substr(52);
            // while (match = RE_KEYVAL.exec(value)) {
            //     properties[match[1]] = match[2];
            // }
    
            var power = lines2Object(ar);
            var on = power.Display_Power__state;
            //var i = power.mScreenOn;
            // power.mSystemReady
            // power.mDisplayReady;
            cb && cb(on === 'ON');
        });
    };
    
    FireTV.prototype.getCurrentApp = function (cb) {
        this.shell('dumpsys window windows | grep mCurrentFocus', function (ar) {
             var value = ar;
             adapter.log.debug('Shell:' + ar);
             var RE_APP = /mCurrentFocus=Window{e\d+\s[a-z0-9]+\s(.*)\/(.*)}/gm;
            // var properties = {};
             var match;
            // value = value.substr(52);
            var currentApp;
            while (match = RE_APP.exec(value)) {
                    self.dev.setImmediately('currentApp', match[1]);
                    self.dev.setImmediately('currentActivity', match[2]);
                    currentApp = match[1];
            //     properties[match[1]] = match[2];
            }
            cb && cb(currentApp);
        });
    };
    
    function getKeyValue(key) {
        var val = ~~key;
        if (val) return val;
        key = key.replace(/"|'|\s/g, '').toUpperCase();
    
        if ((val = adb.Keycode[key]) !== undefined) return val;
        if ((val = adb.Keycode['KEYCODE_DPAD_' + key]) !== undefined) return val;
        val = adb.Keycode['KEYCODE_' + key];
        return val;
    }
    
    
    function buildInputEvent(key, longpress) {
        key = getKeyValue(key);
        var SEP = ' && ';
        //var SEP = '\n';
        var eventNo = 7;
        var cmd =
            //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
            "sendevent /dev/input/event" + eventNo + " 1 " + key + " 1" + SEP +
            "sendevent /dev/input/event" + eventNo + " 0 0 0" + SEP;
        if (longpress) cmd += 'sleep 1';
        cmd +=
            //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
            "sendevent /dev/input/event" + eventNo + " 1 " + key + " 0" + SEP +
            "sendevent /dev/input/event" + eventNo + " 0 0 0";
    
        return cmd;
    }
    
    
    var reInputKey = /^[\"|\'](.*)[\"|\']$/;
    
    FireTV.prototype.inputKeyevent = function (val) {
        if (~~val !== 0) return this.shell("input keyevent " + val);
    
        // (4000, 'DOWN', 1000, 'DOWN', 100, 'DOWN', 'RIGHT', 'RIGHT', 'RIGHT', 'RIGHT', 'ENTER', 500, 'DOWN');
        var ar = val.split(',');
        if (ar.length <= 1) ar = val.split(' ');
        var number, i = 0, delay = 0;
        var self = this;
        //self.stopKeyevents
    
        function doIt() {
            if (i < ar.length && !self.stopKeyevents) {
                var v = ar[i++].trim();
                if ((number = ~~v)) {
                    //adapter.log.debug('sendKeys: number, delay=' + v);
                    delay = number;
                    setTimeout (doIt, delay);
                } else {
                    //adapter.log.debug('sendKeys: ' + v + ' (' + keys[v] + ')');
                    var key;
                    if (reInputKey.test(v)) {
    
                        key = "input text " + normalizeInputText(v.replace(reInputKey, '$1'));
                    } else if (v === 'callback') {
                        self.dev.setImmediately('result', 'callback');
                    } else {
                        key = "input keyevent " + getKeyValue(v);
                    }
                    //console.log('Sending: ' + key + ' i=' + i);
                    self.shell( key, function(lines) {
                        if (i <ar.length && ~~ar[i] > 0) doIt();
                        else setTimeout(doIt, delay);
                    });
                }
            }
            if (self.stopKeyevents) self.stopKeyevents--;
        }
        doIt();
    };
    
    
    FireTV.prototype.frameBuffer = function (val) {
        this.client.framebuffer(this.client.id, 'raw', function(err, stream) {
            if (err || !stream) return;
            adb.util.readAll(stream, function(err, output) {
                err = err;
            });
        });
    };
    
    function normalizeInputText(t) {
        return t.toString().replace(/\s/g, '%s');
    }
    
    FireTV.prototype.onStateChange = function (channel, state, val) {
        var self = this;
        switch(channel) {
            case 'framebuffer':
                this.frameBuffer(val);
                break;
            case usedStateNames.shell.n:
                this.shell(val);
                break;
            case usedStateNames.text.n:
                val = val.replace(/\s/g, '%s');
                this.shell('input text ' + normalizeInputText(val));
                break;
            case 'keys':
                var code = usedStateNames[state].common.code;
                this.shell("input keyevent " + code);
                return true;
            case usedStateNames.startApp.n:
                var appPath = knownAppPathes[val.toLowerCase()];
                if (!appPath) appPath = val;
                var ar = appPath.split('/');
                if (ar.length < 2) appPath += '/.MainActivity';
                this.shell('am start -n ' + appPath);
                break;
            case usedStateNames.stopApp.n:
                var appPath = knownAppPathes[val.toLowerCase()];
                if (!appPath) appPath = val;
                var ar = appPath.split('/');
                this.shell('am force-stop ' + ar[0]);
                break;
            case 'sendevent':
            case usedStateNames.sendKeyCodeArray.n:
            case usedStateNames.sendKeyCode.n:
                this.inputKeyevent(val);
                //this.shell("input keyevent " + val);
                break;
            case usedStateNames.reboot.n:
                this.client.reboot(this.client.id, this.handleCallback.bind(this));
                break;
            case usedStateNames.screencap.n:
                this.client.screencap(this.client.id, this.handleCallback.bind(this));
                break;
            case usedStateNames.swapPower.n:
                this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                return true;
            case 'power':
            case usedStateNames.on.n:
                this.getPowerState(function(on) {
                    if (val !== on) this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                }.bind(this));
                break;
        }
    };
    
    
    function checkIP(cb) {
        if (adapter.config.devices.length) cb && cb();
        cb = undefined;
        var mdns = Mdns({
            timeout: 4,
            //returnOnFirstFound: true,
            name: '_amzn-wplay._tcp.local',
            find: 'amzn.dmgr:'
        });
        mdns.run (function(res) {
            res.removeDup('ip', adapter.config.devices);
            if (!res.length) return cb && cb();
            soef.changeAdapterConfig(adapter, function(config){
                res.forEach(function(dev) {
                    if (!config.devices.find(function(v) {
                        return v.ip === dev.ip;
                    })) {
                        config.devices.push({
                            enabled: true,
                            name: dev.name,
                            ip: dev.ip
                        })
                    }
                });
                if (config.devices.length !== adapter.config.devices.length) {
                    adapter.config.devices = config.devices;
                    if (cb === undefined) {
                       closeAllFireTVs();
                       startFireTVs();
                    }
                }
            }, cb );
        });
    }
    
    
    function checkPATH() {
        var fn, ar = process.env.PATH.split(path.delimiter);
        var exe = isWin ? 'adb.exe' : 'adb';
        ar.find(function(v) {
            if (v.toLowerCase().indexOf('adb') >= 0) {
                var _fn = path.join(v, exe);
                if (soef.existFile(_fn)) {
                    fn = _fn;
                    return true;
                }
            }
            return false;
        });
        return fn;
    }
    
    var defaultMinimalABAndFastboot = 'C:/Program Files (x86)/Minimal ADB and Fastboot/adb.exe';
    function normalizeConfig() {
        var oldAdbPath = adapter.config.adbPath;
        if (!soef.existFile(adapter.config.adbPath)) {
            if (isWin && adapter.config.adbPath && soef.existFile(adapter.config.adbPath + '.exe')) {
                adapter.config.adbPath += '.exe';
            } else {
                var p = adapter.config.adbPath + '/adb';
                p = p.replace(/\\/g, '/').replace(/\/\//g, '/');
                if (!isWin && soef.existFile(p)) {
                    adapter.config.adbPath = p;
                } else if (isWin && soef.existFile(p + '.exe')) {
                    adapter.config.adbPath = p + '.exe';
                } else if (isWin && soef.existFile(defaultMinimalABAndFastboot)) {
                    adapter.config.adbPath = defaultMinimalABAndFastboot;
                } else {
                    adapter.config.adbPath = checkPATH();
                    if (!adapter.config.adbPath) {
                        adapter.log.error('adb executable not found. ' + adapter.config.adbPath);
                        adapter.config.adbPath = 'adb'
                    }
                }
            }
            adapter.config.adbPath = path.normalize(adapter.config.adbPath);
        }
        if (oldAdbPath !== adapter.config.adbPath || adapter.config.devices.unique('ip')) {
            soef.changeAdapterConfig(adapter, function(config) {
                config.devices = adapter.config.devices;
                config.adbPath = adapter.config.adbPath;
            });
        }
     }
    
    
    function startFireTVs(cb) {
        var i = 0;
        function doIt() {
            if (i >= adapter.config.devices.length) return cb && cb();
            var device = adapter.config.devices[i++];
            if (device.enabled) {
                var firetv = new FireTV(device);
                firetv.createStates(doIt);
            } else {
                doIt();
            }
        }
        doIt();
    }
    
    
    function prepareDevices(cb) {
        var re = /^\d*\.\d*\.\d*\.\d*:\d*$/;
        new_g_client();
        g_client.listDevices(function (err, devices) {
            if (err || !devices) return cb && cb(err);
            devices.forEach(function (device) {
                if (!re.test(device.id)) g_client.tcpip(device.id, function (err, port) {
                    if (err || !port) return cb && cb(err);
                    g_client.waitForDevice(device.id, function(err, data) {
                        g_client.getIP(device.id, function(ip) {
                            if (ip) g_client.connect(ip, port, function(err,data) {
                                cb && cb(err);
                            });
                        });
                    });
                });
            })
        })
    }
    
    
    function main() {
    
        normalizeConfig();
        prepareDevices();
    
        soef.deleteOrphanedDevices('ip', adapter.config.devices);
        checkIP(function () {
            startFireTVs(function () {
                trackDevices();
            })
        });
    
        adapter.subscribeStates('*');
        //adapter.subscribeObjects('*');
    }
    
    
    oberstelO J 2 Antworten Letzte Antwort
    0
    • H HenryH

      Hi,

      hab den Adapter fireTV zum laufen gebracht, da das was ich brauche fehlt wollte ich es selbst erweitern.

      Ich hätte gerne zwei Infos, bei denen ich auch weiß wie ich die Abgreifen kann.

      • Aktuelle App
      • Wird gerade was wiedergegeben

      Hab den passenden ADB-Shell Befehl mal in "shell" gesendet, jedoch kommt nichts zurück.
      Dachte dann, ach mach ich halt den sauberen Weg und bau das in den Adapter als Datenpunkt, jedoch komme ich nicht weiter.

      Der Datenpunkt wird nicht befüllt, aber angelegt. Auch bekomme ich keine Logmeldungen.

      Hier meine angepasste firetv.js:

      "use strict";
      
      var soef = require(`${__dirname}/lib/dontBeSoSoef`),
          adb = require('adbkit'),
          path = require('path'),
          Mdns = require('mdns-discovery');
      
      let Client;
      try {
          Client = require('./node_modules/adbkit/lib/adb/client.js');
      } catch (e) {
          Client = require('../adbkit/lib/adb/client');
      }
      
      soef.extendAll();
      
      Client.prototype.shellEx = function(id, command, cb) {
          //this.parent.shell.call( this, id, command, function (err, stream) {
          this.shell(id, command, function (err, stream) {
              if (err || !stream) return cb & cb(err, 0);
              adb.util.readAll(stream, function (err, output) {
                  if (err || !stream) return cb && cb(err);
                  var ar = output.toString().split('\r\n');
                  ar.length--;
                  for (var i=ar.length-1; i > ar.length-10; i++) {
                      adapter.log.debug(ar[i]);
                  }
                  cb && cb(0, ar);
              });
          })
      };
      
      // Client.prototype.shell1 = function (id, command, cb) {
      //     return this.shellEx(id, command, function (err, ar) {
      //         cb && cb(err, (ar && ar.length) ? ar[0] : '');
      //     });
      // };
      
      Client.prototype.getIP = function(id, cb) {
          var self = this;
          this.getProperties(id, function (err, properties) {
              if (!err && properties) {
                  var ip = soef.getProp(properties, "dhcp.eth0.ipaddress");
                  ip = ip || soef.getProp(properties, "dhcp.wlan0.ipaddress");
                  if (ip) return cb && cb(0, ip);
              }
              self.shellEx(id, "ifconfig wlan0", function (err, ar) {
                  if (err || !ar) return cb && cb('');
                  ar.forEach(function (line) {
                      var a = line.trim().split('  ');
                      if (a && a.length) {
                          a = a[0].split(':');
                          if (a && a.length && a[0] === 'inet addr') {
                              ip = a [1];
                              if (ip) return cb && cb(ip);
                          }
                      }
                  });
                  cb && cb('');
              });
          });
      };
      
      
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      var fireTVs = {};
      var g_client;
      var isWin = process.platform === 'win32';
      
      var knownAppPathes = {
          kodi:     'org.xbmc.kodi/.Splash',
          xbmc:     'org.xbmc.kodi/.Splash',
          netflix:  'com.netflix.ninja',
          tvnow:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
          nowtv:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
          zdf:      'com.zdf.android.mediathek',
          ard:      'com.daserste.daserste',
          daserste: 'com.daserste.daserste'
      };
      
      //am start -n com.netflix.ninja
      //am start -W -S -n com.netflix.ninja/.MainActivityam
      
      var adapter = soef.Adapter (
          main,
          onStateChange,
          onUnload,
          onMessage,
          'firetv'
      );
      
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      var usedStateNames = {
          online:             { n: 'online',      val: false, common: { write: false, min: false, max: true }},
          currentApp:         { n: 'currentApp',  val: '',    common: { write: false }},
          currentActivity:    { n: 'currentActivity', val: '',common: { write: false }},
          startApp:           { n: 'startApp',    val: '',    common: { desc: 'start an application e.g.: com.netflix.ninja/.MainActivity'}},
          stopApp:            { n: 'stopApp',     val: '',    common: { desc: 'stops an application e.g.: com.netflix.ninja'}},
          sendKeyCode:        { n: 'sendKeyCode', val: 0,     common: { }},
          sendKeyCodeArray:   { n: '',            val: '',    common: { desc: 'Can be an array of keys and delays. e.g.: 4000, DOWN, 100, DOWN, DOWN, LEFT, ENTER, 5000, LEFT' }},
          reboot:             { n: 'reboot',      val: false, common: { min: false, max: true}},
          screencap:          { n: 'screencap',   val: false, common: { min: false, max: true}},
          result:             { n: 'result',      val: '',    common: { write: false }},
          swapPower:          { n: 'swapPower',   val: false, common: { min: false, max: true}},
          on:                 { n: 'on',          val: false, common: { min: false, max: true}},
          state:              { n: 'state',       val: '',    common: { }},
          shell:              { n: 'shell',       val: '',    common: { desc: 'send an adb shell command'}},
          text:               { n: 'text',        val: '',    common: { desc: 'send "text" to the device'}},
          sendevent:          { n: 'sendevent',   val: '',    common: { } },
      
          //framebuffer:        { n: 'framebuffer', val: '',    common: { } },
      
          enter:              { n: 'keys.enter',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ENTER }},
          left:               { n: 'keys.left',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_LEFT }},
          right:              { n: 'keys.right',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_RIGHT }},
          up:                 { n: 'keys.up',     val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_UP }},
          down:               { n: 'keys.down',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_DOWN }},
          home:               { n: 'keys.home',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_HOME }},
          back:               { n: 'keys.back',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_BACK }},
          menu:               { n: 'keys.menu',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_MENU }},
          escape:             { n: 'keys.escape', val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ESCAPE}}
      };
      for (var i in usedStateNames) {
          var o = usedStateNames[i];
          if (!o.n) o.n = i;
      }
      
      
      function prepareStates() {
          var o = {};
          for (var i in adb.Keycode) {
              o[adb.Keycode[i]] = i.substr(8);
          }
          usedStateNames.sendKeyCode.common.states = o;
      }
      prepareStates();
      
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      function onStateChange(id, state) {
          var dcs = adapter.idToDCS(id);
          var ftv = fireTVs[dcs.device];
          if (ftv) {
              if (ftv.onStateChange(dcs.channel, dcs.state, state.val) === true) {
                  ftv.dev.setImmediately(soef.ns.no(id), false);
              }
          }
      }
      
      
      function onMessage (obj) {
          if (!obj) return;
          switch (obj.command) {
              case 'discovery':
                  var mdns = Mdns({
                      timeout: 3,
                      name: '_amzn-wplay._tcp.local',
                      find: 'amzn.dmgr:'
                  });
                  mdns.setFilter('ip', adapter.config.devices).run (function(res) {
                      if (obj.callback) {
                          res.forEach(function(v) {
                              v.enabled = true;
                          });
                          adapter.sendTo (obj.from, obj.command, JSON.stringify(res), obj.callback);
                      }
                  });
                  return true;
              default:
                  adapter.log.warn("Unknown command: " + obj.command);
                  break;
          }
          if (obj.callback) adapter.sendTo (obj.from, obj.command, obj.message, obj.callback);
          return true;
      }
      
      
      function closeAllFireTVs() {
          for (var i in fireTVs) {
              fireTVs[i].close();
              delete fireTVs[i];
          }
      
      }
      
      function onUnload(callback) {
          closeAllFireTVs();
          g_client.close();
          callback && callback();
      }
      
      function new_g_client() {
          if (g_client) return;
          g_client = adb.createClient({bin: adapter.config.adbPath});
      }
      
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      function trackDevices() {
      
          function set(device, val) {
              if (!device || !device.id) return;
              var ar = device.id.split(':');
              var ftv = fireTVs[normalizedName(ar[0])];
              if (ftv) {
                  ftv.setOnline(val);
                  ftv.updatePowerState();
                  ftv.updateCurrentApp();
                  ftv.updateState();
              }
          }
          new_g_client();
          g_client.trackDevices()
              .then(function (tracker) {
                  tracker.on('add', function (device) {
                      set(device, true);
                      adapter.log.debug('Device ' + device.id + ' + type=' + device.type + ' was plugged in');
                  });
                  tracker.on('remove', function (device) {
                      set(device, false);
                      adapter.log.debug('Device ' + device.id + ' was unplugged');
                  });
                  tracker.on('end', function () {
                      adapter.log.debug('Tracking stopped');
                  });
              })
              .catch(function (err) {
                  adapter.log.debug('Something went wrong:' + err.message)
              })
      }
      
      
      ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      
      var FireTV = function (entry) {
          this.dev = new devices.CDevice(entry.ip, entry.name);
          this.id = entry.ip;
          adapter.log.debug("FireTV: " + entry.ip);
          var d = this.dev.getFullId('');
          fireTVs [d] = this;
      };
      
      
      FireTV.prototype.startClient = function(cb) {
          var self = this;
          this.client = adb.createClient({ bin: adapter.config.adbPath });
          this.client.connect(this.id, 5555, function(err, id) {
              if (err || !id) {
                  adapter.log.error('can not connect to ' + self.id + ' Error=' + err.message);
                  return;
              }
              self.client.id = id;
              self.client.getState(id, function(err,state) {
                  adapter.log.debug('Connected to ' + self.id + ' id=' + id + ((!err && state) ? ' state=' + state : ""));
                  self.updateState(state);
              });
      
              // self.client.getProperties(id, function(err, properties) {
              // });
              // self.client.getPackages(id, function(err, packages) {
              //     if (err || !packages) return;
              // });
      
              self.client.version(function(err, version) {
                  self.getAndroidVersion(function(androidVersion) {
                      self.getAPILevel(function (apiLevel) {
                          soef.log("%s: ADB version: %s, Android Version: %s, API Level: %s", self.id, version, androidVersion, apiLevel);
                      });
                  });
              });
              self.updatePowerState();
              self.updateCurrentApp();
          });
          cb && cb();
      };
      
      
      FireTV.prototype.createStates = function (cb) {
          for (var j in usedStateNames) {
              var st = Object.assign({}, usedStateNames[j]);
              this.dev.createNew(st.n, st);
          }
          devices.update(function() {
              this.startClient(cb);
          }.bind(this));
      };
      
      
      FireTV.prototype.close = function() {
          if (this.client && this.client.id) {
              this.client.disconnect(this.client.id).catch(function (err) {
                  adapter.log.debug('Something went wrong:' + err.message)
              });
              this.client.kill(function(err) {
                   if (err) adapter.log('error killing adb server: ' + err.message);
              });
              this.client = undefined;
          }
      };
      
      FireTV.prototype.getAndroidVersion = function (cb) {
          return this.shell1('getprop ro.build.version.release', cb);
      };
      
      FireTV.prototype.getAPILevel = function (cb) {
          return this.shell1('getprop ro.build.version.sdk', cb);
      };
      
      FireTV.prototype.setOnline = function (online) {
          this.dev.setImmediately(usedStateNames.online.n, !!online);
      };
      
      
      FireTV.prototype.handleCallback = function (err, stream, cb) {
          if (err || !stream) {
              adapter.log.error('ID: ' + this.id + ' Error=' + err.message);
              if (err && err.message) this.dev.setImmediately('error', err.message);
              return cb && cb();
          }
          var self = this;
          adb.util.readAll(stream, function(err, output) {
              if (!err && output) {
                  var ar = output.toString().split('\r\n');
                  ar.length--;
                  // for (var i = Math.max(0, ar.length-10); i < ar.length; i++) {
                  //     var line = ar[i];
                  //     adapter.log.debug(line);
                  //     self.dev.setImmediately('result', line);
                  // }
                  if (ar.length < 10) ar.forEach(function (line) {
                      adapter.log.debug(line);
                      self.dev.setImmediately('result', line);
                  });
              }
              if (cb) cb (ar);
          });
      };
      
      
      FireTV.prototype.shell1 /*Line*/ = function (cmd, cb) {
          this.shell (cmd, function(ar) {
              if (ar && ar.length) return cb && cb(ar[0]);
              cb && cb('');
          })
      };
      
      FireTV.prototype.shell = function (command, cb) {
          if (!this.client || !this.client.id) return cb && cb('client.id not set');
          this.client.shell(this.client.id, command, function(err, stream) {
              this.handleCallback(err, stream, cb);
          }.bind(this));
      };
      
      
      function lines2Object(lines) {
          var o = {};
          if (!lines) return o;
          if (typeof lines === 'string') lines = lines.split('\r\n');
          lines.forEach(function(line) {
              line = line.trim().replace(/ |:/g, '_');
              var ar = line.split('=');
               if (ar && ar.length >= 2) {
                   o [ar[0]] = valtype(ar[1]);
               }
          });
          return o;
      }
      
      
      FireTV.prototype.updatePowerState = function (cb) {
          this.getPowerState(function (on) {
              this.dev.setImmediately(usedStateNames.on.n, on);
              cb && cb(on);
          }.bind(this));
      };
      FireTV.prototype.updateCurrentApp = function (cb) {
          this.getCurrentApp(function (currentApp) {
              this.dev.setImmediately(usedStateNames.currentApp.n, currentApp);
              cb && cb(currentApp);
          }.bind(this));
      };
      FireTV.prototype.updateState = function (state) {
          this.dev.setImmediately(usedStateNames.state.n, state);
      };
      
      
      FireTV.prototype.getPowerState = function (cb) {
          this.shell('dumpsys power', function (ar) {
              // var value = ar.join('\r');
              // var RE_KEYVAL = /^\s*(\S*)=(\S)\r?$/gm;
              // var properties = {};
              // var match;
              // value = value.substr(52);
              // while (match = RE_KEYVAL.exec(value)) {
              //     properties[match[1]] = match[2];
              // }
      
              var power = lines2Object(ar);
              var on = power.Display_Power__state;
              //var i = power.mScreenOn;
              // power.mSystemReady
              // power.mDisplayReady;
              cb && cb(on === 'ON');
          });
      };
      
      FireTV.prototype.getCurrentApp = function (cb) {
          this.shell('dumpsys window windows | grep mCurrentFocus', function (ar) {
               var value = ar;
               adapter.log.debug('Shell:' + ar);
               var RE_APP = /mCurrentFocus=Window{e\d+\s[a-z0-9]+\s(.*)\/(.*)}/gm;
              // var properties = {};
               var match;
              // value = value.substr(52);
              var currentApp;
              while (match = RE_APP.exec(value)) {
                      self.dev.setImmediately('currentApp', match[1]);
                      self.dev.setImmediately('currentActivity', match[2]);
                      currentApp = match[1];
              //     properties[match[1]] = match[2];
              }
              cb && cb(currentApp);
          });
      };
      
      function getKeyValue(key) {
          var val = ~~key;
          if (val) return val;
          key = key.replace(/"|'|\s/g, '').toUpperCase();
      
          if ((val = adb.Keycode[key]) !== undefined) return val;
          if ((val = adb.Keycode['KEYCODE_DPAD_' + key]) !== undefined) return val;
          val = adb.Keycode['KEYCODE_' + key];
          return val;
      }
      
      
      function buildInputEvent(key, longpress) {
          key = getKeyValue(key);
          var SEP = ' && ';
          //var SEP = '\n';
          var eventNo = 7;
          var cmd =
              //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
              "sendevent /dev/input/event" + eventNo + " 1 " + key + " 1" + SEP +
              "sendevent /dev/input/event" + eventNo + " 0 0 0" + SEP;
          if (longpress) cmd += 'sleep 1';
          cmd +=
              //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
              "sendevent /dev/input/event" + eventNo + " 1 " + key + " 0" + SEP +
              "sendevent /dev/input/event" + eventNo + " 0 0 0";
      
          return cmd;
      }
      
      
      var reInputKey = /^[\"|\'](.*)[\"|\']$/;
      
      FireTV.prototype.inputKeyevent = function (val) {
          if (~~val !== 0) return this.shell("input keyevent " + val);
      
          // (4000, 'DOWN', 1000, 'DOWN', 100, 'DOWN', 'RIGHT', 'RIGHT', 'RIGHT', 'RIGHT', 'ENTER', 500, 'DOWN');
          var ar = val.split(',');
          if (ar.length <= 1) ar = val.split(' ');
          var number, i = 0, delay = 0;
          var self = this;
          //self.stopKeyevents
      
          function doIt() {
              if (i < ar.length && !self.stopKeyevents) {
                  var v = ar[i++].trim();
                  if ((number = ~~v)) {
                      //adapter.log.debug('sendKeys: number, delay=' + v);
                      delay = number;
                      setTimeout (doIt, delay);
                  } else {
                      //adapter.log.debug('sendKeys: ' + v + ' (' + keys[v] + ')');
                      var key;
                      if (reInputKey.test(v)) {
      
                          key = "input text " + normalizeInputText(v.replace(reInputKey, '$1'));
                      } else if (v === 'callback') {
                          self.dev.setImmediately('result', 'callback');
                      } else {
                          key = "input keyevent " + getKeyValue(v);
                      }
                      //console.log('Sending: ' + key + ' i=' + i);
                      self.shell( key, function(lines) {
                          if (i <ar.length && ~~ar[i] > 0) doIt();
                          else setTimeout(doIt, delay);
                      });
                  }
              }
              if (self.stopKeyevents) self.stopKeyevents--;
          }
          doIt();
      };
      
      
      FireTV.prototype.frameBuffer = function (val) {
          this.client.framebuffer(this.client.id, 'raw', function(err, stream) {
              if (err || !stream) return;
              adb.util.readAll(stream, function(err, output) {
                  err = err;
              });
          });
      };
      
      function normalizeInputText(t) {
          return t.toString().replace(/\s/g, '%s');
      }
      
      FireTV.prototype.onStateChange = function (channel, state, val) {
          var self = this;
          switch(channel) {
              case 'framebuffer':
                  this.frameBuffer(val);
                  break;
              case usedStateNames.shell.n:
                  this.shell(val);
                  break;
              case usedStateNames.text.n:
                  val = val.replace(/\s/g, '%s');
                  this.shell('input text ' + normalizeInputText(val));
                  break;
              case 'keys':
                  var code = usedStateNames[state].common.code;
                  this.shell("input keyevent " + code);
                  return true;
              case usedStateNames.startApp.n:
                  var appPath = knownAppPathes[val.toLowerCase()];
                  if (!appPath) appPath = val;
                  var ar = appPath.split('/');
                  if (ar.length < 2) appPath += '/.MainActivity';
                  this.shell('am start -n ' + appPath);
                  break;
              case usedStateNames.stopApp.n:
                  var appPath = knownAppPathes[val.toLowerCase()];
                  if (!appPath) appPath = val;
                  var ar = appPath.split('/');
                  this.shell('am force-stop ' + ar[0]);
                  break;
              case 'sendevent':
              case usedStateNames.sendKeyCodeArray.n:
              case usedStateNames.sendKeyCode.n:
                  this.inputKeyevent(val);
                  //this.shell("input keyevent " + val);
                  break;
              case usedStateNames.reboot.n:
                  this.client.reboot(this.client.id, this.handleCallback.bind(this));
                  break;
              case usedStateNames.screencap.n:
                  this.client.screencap(this.client.id, this.handleCallback.bind(this));
                  break;
              case usedStateNames.swapPower.n:
                  this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                  return true;
              case 'power':
              case usedStateNames.on.n:
                  this.getPowerState(function(on) {
                      if (val !== on) this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                  }.bind(this));
                  break;
          }
      };
      
      
      function checkIP(cb) {
          if (adapter.config.devices.length) cb && cb();
          cb = undefined;
          var mdns = Mdns({
              timeout: 4,
              //returnOnFirstFound: true,
              name: '_amzn-wplay._tcp.local',
              find: 'amzn.dmgr:'
          });
          mdns.run (function(res) {
              res.removeDup('ip', adapter.config.devices);
              if (!res.length) return cb && cb();
              soef.changeAdapterConfig(adapter, function(config){
                  res.forEach(function(dev) {
                      if (!config.devices.find(function(v) {
                          return v.ip === dev.ip;
                      })) {
                          config.devices.push({
                              enabled: true,
                              name: dev.name,
                              ip: dev.ip
                          })
                      }
                  });
                  if (config.devices.length !== adapter.config.devices.length) {
                      adapter.config.devices = config.devices;
                      if (cb === undefined) {
                         closeAllFireTVs();
                         startFireTVs();
                      }
                  }
              }, cb );
          });
      }
      
      
      function checkPATH() {
          var fn, ar = process.env.PATH.split(path.delimiter);
          var exe = isWin ? 'adb.exe' : 'adb';
          ar.find(function(v) {
              if (v.toLowerCase().indexOf('adb') >= 0) {
                  var _fn = path.join(v, exe);
                  if (soef.existFile(_fn)) {
                      fn = _fn;
                      return true;
                  }
              }
              return false;
          });
          return fn;
      }
      
      var defaultMinimalABAndFastboot = 'C:/Program Files (x86)/Minimal ADB and Fastboot/adb.exe';
      function normalizeConfig() {
          var oldAdbPath = adapter.config.adbPath;
          if (!soef.existFile(adapter.config.adbPath)) {
              if (isWin && adapter.config.adbPath && soef.existFile(adapter.config.adbPath + '.exe')) {
                  adapter.config.adbPath += '.exe';
              } else {
                  var p = adapter.config.adbPath + '/adb';
                  p = p.replace(/\\/g, '/').replace(/\/\//g, '/');
                  if (!isWin && soef.existFile(p)) {
                      adapter.config.adbPath = p;
                  } else if (isWin && soef.existFile(p + '.exe')) {
                      adapter.config.adbPath = p + '.exe';
                  } else if (isWin && soef.existFile(defaultMinimalABAndFastboot)) {
                      adapter.config.adbPath = defaultMinimalABAndFastboot;
                  } else {
                      adapter.config.adbPath = checkPATH();
                      if (!adapter.config.adbPath) {
                          adapter.log.error('adb executable not found. ' + adapter.config.adbPath);
                          adapter.config.adbPath = 'adb'
                      }
                  }
              }
              adapter.config.adbPath = path.normalize(adapter.config.adbPath);
          }
          if (oldAdbPath !== adapter.config.adbPath || adapter.config.devices.unique('ip')) {
              soef.changeAdapterConfig(adapter, function(config) {
                  config.devices = adapter.config.devices;
                  config.adbPath = adapter.config.adbPath;
              });
          }
       }
      
      
      function startFireTVs(cb) {
          var i = 0;
          function doIt() {
              if (i >= adapter.config.devices.length) return cb && cb();
              var device = adapter.config.devices[i++];
              if (device.enabled) {
                  var firetv = new FireTV(device);
                  firetv.createStates(doIt);
              } else {
                  doIt();
              }
          }
          doIt();
      }
      
      
      function prepareDevices(cb) {
          var re = /^\d*\.\d*\.\d*\.\d*:\d*$/;
          new_g_client();
          g_client.listDevices(function (err, devices) {
              if (err || !devices) return cb && cb(err);
              devices.forEach(function (device) {
                  if (!re.test(device.id)) g_client.tcpip(device.id, function (err, port) {
                      if (err || !port) return cb && cb(err);
                      g_client.waitForDevice(device.id, function(err, data) {
                          g_client.getIP(device.id, function(ip) {
                              if (ip) g_client.connect(ip, port, function(err,data) {
                                  cb && cb(err);
                              });
                          });
                      });
                  });
              })
          })
      }
      
      
      function main() {
      
          normalizeConfig();
          prepareDevices();
      
          soef.deleteOrphanedDevices('ip', adapter.config.devices);
          checkIP(function () {
              startFireTVs(function () {
                  trackDevices();
              })
          });
      
          adapter.subscribeStates('*');
          //adapter.subscribeObjects('*');
      }
      
      
      oberstelO Offline
      oberstelO Offline
      oberstel
      schrieb am zuletzt editiert von
      #2

      @HenryH said in Adapter: fireTv:

      Dachte dann, ach mach ich halt den sauberen Weg und bau das in den Adapter als Datenpunkt, jedoch komme ich nicht weiter.

      Hallo Henry,

      bis Du hier schon weitergekommen?

      Grüße
      oberstel

      H 1 Antwort Letzte Antwort
      0
      • oberstelO oberstel

        @HenryH said in Adapter: fireTv:

        Dachte dann, ach mach ich halt den sauberen Weg und bau das in den Adapter als Datenpunkt, jedoch komme ich nicht weiter.

        Hallo Henry,

        bis Du hier schon weitergekommen?

        Grüße
        oberstel

        H Offline
        H Offline
        HenryH
        schrieb am zuletzt editiert von
        #3

        Hi @oberstel,

        leider nicht.
        Habe das dann auch nicht mehr weiter verfolgt, da die ADB Schnittstelle unzuverlässig auf dem FireTV Stick läuft und häufig deaktiviert und wieder aktiviert werden muss um dann wieder zu funktionieren.
        Habe zwar gefunden dass es Schnittstellen von Amazon gibt, jedoch schien das eher Aufwendig und hatte nicht ganz verstanden wie das genau funktioniert.

        Gruß

        1 Antwort Letzte Antwort
        0
        • H HenryH

          Hi,

          hab den Adapter fireTV zum laufen gebracht, da das was ich brauche fehlt wollte ich es selbst erweitern.

          Ich hätte gerne zwei Infos, bei denen ich auch weiß wie ich die Abgreifen kann.

          • Aktuelle App
          • Wird gerade was wiedergegeben

          Hab den passenden ADB-Shell Befehl mal in "shell" gesendet, jedoch kommt nichts zurück.
          Dachte dann, ach mach ich halt den sauberen Weg und bau das in den Adapter als Datenpunkt, jedoch komme ich nicht weiter.

          Der Datenpunkt wird nicht befüllt, aber angelegt. Auch bekomme ich keine Logmeldungen.

          Hier meine angepasste firetv.js:

          "use strict";
          
          var soef = require(`${__dirname}/lib/dontBeSoSoef`),
              adb = require('adbkit'),
              path = require('path'),
              Mdns = require('mdns-discovery');
          
          let Client;
          try {
              Client = require('./node_modules/adbkit/lib/adb/client.js');
          } catch (e) {
              Client = require('../adbkit/lib/adb/client');
          }
          
          soef.extendAll();
          
          Client.prototype.shellEx = function(id, command, cb) {
              //this.parent.shell.call( this, id, command, function (err, stream) {
              this.shell(id, command, function (err, stream) {
                  if (err || !stream) return cb & cb(err, 0);
                  adb.util.readAll(stream, function (err, output) {
                      if (err || !stream) return cb && cb(err);
                      var ar = output.toString().split('\r\n');
                      ar.length--;
                      for (var i=ar.length-1; i > ar.length-10; i++) {
                          adapter.log.debug(ar[i]);
                      }
                      cb && cb(0, ar);
                  });
              })
          };
          
          // Client.prototype.shell1 = function (id, command, cb) {
          //     return this.shellEx(id, command, function (err, ar) {
          //         cb && cb(err, (ar && ar.length) ? ar[0] : '');
          //     });
          // };
          
          Client.prototype.getIP = function(id, cb) {
              var self = this;
              this.getProperties(id, function (err, properties) {
                  if (!err && properties) {
                      var ip = soef.getProp(properties, "dhcp.eth0.ipaddress");
                      ip = ip || soef.getProp(properties, "dhcp.wlan0.ipaddress");
                      if (ip) return cb && cb(0, ip);
                  }
                  self.shellEx(id, "ifconfig wlan0", function (err, ar) {
                      if (err || !ar) return cb && cb('');
                      ar.forEach(function (line) {
                          var a = line.trim().split('  ');
                          if (a && a.length) {
                              a = a[0].split(':');
                              if (a && a.length && a[0] === 'inet addr') {
                                  ip = a [1];
                                  if (ip) return cb && cb(ip);
                              }
                          }
                      });
                      cb && cb('');
                  });
              });
          };
          
          
          ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          
          var fireTVs = {};
          var g_client;
          var isWin = process.platform === 'win32';
          
          var knownAppPathes = {
              kodi:     'org.xbmc.kodi/.Splash',
              xbmc:     'org.xbmc.kodi/.Splash',
              netflix:  'com.netflix.ninja',
              tvnow:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
              nowtv:    'de.cbc.tvnow.firetv/de.cbc.tvnowfiretv.MainActivity',
              zdf:      'com.zdf.android.mediathek',
              ard:      'com.daserste.daserste',
              daserste: 'com.daserste.daserste'
          };
          
          //am start -n com.netflix.ninja
          //am start -W -S -n com.netflix.ninja/.MainActivityam
          
          var adapter = soef.Adapter (
              main,
              onStateChange,
              onUnload,
              onMessage,
              'firetv'
          );
          
          ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          
          var usedStateNames = {
              online:             { n: 'online',      val: false, common: { write: false, min: false, max: true }},
              currentApp:         { n: 'currentApp',  val: '',    common: { write: false }},
              currentActivity:    { n: 'currentActivity', val: '',common: { write: false }},
              startApp:           { n: 'startApp',    val: '',    common: { desc: 'start an application e.g.: com.netflix.ninja/.MainActivity'}},
              stopApp:            { n: 'stopApp',     val: '',    common: { desc: 'stops an application e.g.: com.netflix.ninja'}},
              sendKeyCode:        { n: 'sendKeyCode', val: 0,     common: { }},
              sendKeyCodeArray:   { n: '',            val: '',    common: { desc: 'Can be an array of keys and delays. e.g.: 4000, DOWN, 100, DOWN, DOWN, LEFT, ENTER, 5000, LEFT' }},
              reboot:             { n: 'reboot',      val: false, common: { min: false, max: true}},
              screencap:          { n: 'screencap',   val: false, common: { min: false, max: true}},
              result:             { n: 'result',      val: '',    common: { write: false }},
              swapPower:          { n: 'swapPower',   val: false, common: { min: false, max: true}},
              on:                 { n: 'on',          val: false, common: { min: false, max: true}},
              state:              { n: 'state',       val: '',    common: { }},
              shell:              { n: 'shell',       val: '',    common: { desc: 'send an adb shell command'}},
              text:               { n: 'text',        val: '',    common: { desc: 'send "text" to the device'}},
              sendevent:          { n: 'sendevent',   val: '',    common: { } },
          
              //framebuffer:        { n: 'framebuffer', val: '',    common: { } },
          
              enter:              { n: 'keys.enter',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ENTER }},
              left:               { n: 'keys.left',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_LEFT }},
              right:              { n: 'keys.right',  val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_RIGHT }},
              up:                 { n: 'keys.up',     val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_UP }},
              down:               { n: 'keys.down',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_DPAD_DOWN }},
              home:               { n: 'keys.home',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_HOME }},
              back:               { n: 'keys.back',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_BACK }},
              menu:               { n: 'keys.menu',   val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_MENU }},
              escape:             { n: 'keys.escape', val: false, common: { min: false, max: true, code: adb.Keycode.KEYCODE_ESCAPE}}
          };
          for (var i in usedStateNames) {
              var o = usedStateNames[i];
              if (!o.n) o.n = i;
          }
          
          
          function prepareStates() {
              var o = {};
              for (var i in adb.Keycode) {
                  o[adb.Keycode[i]] = i.substr(8);
              }
              usedStateNames.sendKeyCode.common.states = o;
          }
          prepareStates();
          
          ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          
          function onStateChange(id, state) {
              var dcs = adapter.idToDCS(id);
              var ftv = fireTVs[dcs.device];
              if (ftv) {
                  if (ftv.onStateChange(dcs.channel, dcs.state, state.val) === true) {
                      ftv.dev.setImmediately(soef.ns.no(id), false);
                  }
              }
          }
          
          
          function onMessage (obj) {
              if (!obj) return;
              switch (obj.command) {
                  case 'discovery':
                      var mdns = Mdns({
                          timeout: 3,
                          name: '_amzn-wplay._tcp.local',
                          find: 'amzn.dmgr:'
                      });
                      mdns.setFilter('ip', adapter.config.devices).run (function(res) {
                          if (obj.callback) {
                              res.forEach(function(v) {
                                  v.enabled = true;
                              });
                              adapter.sendTo (obj.from, obj.command, JSON.stringify(res), obj.callback);
                          }
                      });
                      return true;
                  default:
                      adapter.log.warn("Unknown command: " + obj.command);
                      break;
              }
              if (obj.callback) adapter.sendTo (obj.from, obj.command, obj.message, obj.callback);
              return true;
          }
          
          
          function closeAllFireTVs() {
              for (var i in fireTVs) {
                  fireTVs[i].close();
                  delete fireTVs[i];
              }
          
          }
          
          function onUnload(callback) {
              closeAllFireTVs();
              g_client.close();
              callback && callback();
          }
          
          function new_g_client() {
              if (g_client) return;
              g_client = adb.createClient({bin: adapter.config.adbPath});
          }
          
          ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          
          function trackDevices() {
          
              function set(device, val) {
                  if (!device || !device.id) return;
                  var ar = device.id.split(':');
                  var ftv = fireTVs[normalizedName(ar[0])];
                  if (ftv) {
                      ftv.setOnline(val);
                      ftv.updatePowerState();
                      ftv.updateCurrentApp();
                      ftv.updateState();
                  }
              }
              new_g_client();
              g_client.trackDevices()
                  .then(function (tracker) {
                      tracker.on('add', function (device) {
                          set(device, true);
                          adapter.log.debug('Device ' + device.id + ' + type=' + device.type + ' was plugged in');
                      });
                      tracker.on('remove', function (device) {
                          set(device, false);
                          adapter.log.debug('Device ' + device.id + ' was unplugged');
                      });
                      tracker.on('end', function () {
                          adapter.log.debug('Tracking stopped');
                      });
                  })
                  .catch(function (err) {
                      adapter.log.debug('Something went wrong:' + err.message)
                  })
          }
          
          
          ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
          
          var FireTV = function (entry) {
              this.dev = new devices.CDevice(entry.ip, entry.name);
              this.id = entry.ip;
              adapter.log.debug("FireTV: " + entry.ip);
              var d = this.dev.getFullId('');
              fireTVs [d] = this;
          };
          
          
          FireTV.prototype.startClient = function(cb) {
              var self = this;
              this.client = adb.createClient({ bin: adapter.config.adbPath });
              this.client.connect(this.id, 5555, function(err, id) {
                  if (err || !id) {
                      adapter.log.error('can not connect to ' + self.id + ' Error=' + err.message);
                      return;
                  }
                  self.client.id = id;
                  self.client.getState(id, function(err,state) {
                      adapter.log.debug('Connected to ' + self.id + ' id=' + id + ((!err && state) ? ' state=' + state : ""));
                      self.updateState(state);
                  });
          
                  // self.client.getProperties(id, function(err, properties) {
                  // });
                  // self.client.getPackages(id, function(err, packages) {
                  //     if (err || !packages) return;
                  // });
          
                  self.client.version(function(err, version) {
                      self.getAndroidVersion(function(androidVersion) {
                          self.getAPILevel(function (apiLevel) {
                              soef.log("%s: ADB version: %s, Android Version: %s, API Level: %s", self.id, version, androidVersion, apiLevel);
                          });
                      });
                  });
                  self.updatePowerState();
                  self.updateCurrentApp();
              });
              cb && cb();
          };
          
          
          FireTV.prototype.createStates = function (cb) {
              for (var j in usedStateNames) {
                  var st = Object.assign({}, usedStateNames[j]);
                  this.dev.createNew(st.n, st);
              }
              devices.update(function() {
                  this.startClient(cb);
              }.bind(this));
          };
          
          
          FireTV.prototype.close = function() {
              if (this.client && this.client.id) {
                  this.client.disconnect(this.client.id).catch(function (err) {
                      adapter.log.debug('Something went wrong:' + err.message)
                  });
                  this.client.kill(function(err) {
                       if (err) adapter.log('error killing adb server: ' + err.message);
                  });
                  this.client = undefined;
              }
          };
          
          FireTV.prototype.getAndroidVersion = function (cb) {
              return this.shell1('getprop ro.build.version.release', cb);
          };
          
          FireTV.prototype.getAPILevel = function (cb) {
              return this.shell1('getprop ro.build.version.sdk', cb);
          };
          
          FireTV.prototype.setOnline = function (online) {
              this.dev.setImmediately(usedStateNames.online.n, !!online);
          };
          
          
          FireTV.prototype.handleCallback = function (err, stream, cb) {
              if (err || !stream) {
                  adapter.log.error('ID: ' + this.id + ' Error=' + err.message);
                  if (err && err.message) this.dev.setImmediately('error', err.message);
                  return cb && cb();
              }
              var self = this;
              adb.util.readAll(stream, function(err, output) {
                  if (!err && output) {
                      var ar = output.toString().split('\r\n');
                      ar.length--;
                      // for (var i = Math.max(0, ar.length-10); i < ar.length; i++) {
                      //     var line = ar[i];
                      //     adapter.log.debug(line);
                      //     self.dev.setImmediately('result', line);
                      // }
                      if (ar.length < 10) ar.forEach(function (line) {
                          adapter.log.debug(line);
                          self.dev.setImmediately('result', line);
                      });
                  }
                  if (cb) cb (ar);
              });
          };
          
          
          FireTV.prototype.shell1 /*Line*/ = function (cmd, cb) {
              this.shell (cmd, function(ar) {
                  if (ar && ar.length) return cb && cb(ar[0]);
                  cb && cb('');
              })
          };
          
          FireTV.prototype.shell = function (command, cb) {
              if (!this.client || !this.client.id) return cb && cb('client.id not set');
              this.client.shell(this.client.id, command, function(err, stream) {
                  this.handleCallback(err, stream, cb);
              }.bind(this));
          };
          
          
          function lines2Object(lines) {
              var o = {};
              if (!lines) return o;
              if (typeof lines === 'string') lines = lines.split('\r\n');
              lines.forEach(function(line) {
                  line = line.trim().replace(/ |:/g, '_');
                  var ar = line.split('=');
                   if (ar && ar.length >= 2) {
                       o [ar[0]] = valtype(ar[1]);
                   }
              });
              return o;
          }
          
          
          FireTV.prototype.updatePowerState = function (cb) {
              this.getPowerState(function (on) {
                  this.dev.setImmediately(usedStateNames.on.n, on);
                  cb && cb(on);
              }.bind(this));
          };
          FireTV.prototype.updateCurrentApp = function (cb) {
              this.getCurrentApp(function (currentApp) {
                  this.dev.setImmediately(usedStateNames.currentApp.n, currentApp);
                  cb && cb(currentApp);
              }.bind(this));
          };
          FireTV.prototype.updateState = function (state) {
              this.dev.setImmediately(usedStateNames.state.n, state);
          };
          
          
          FireTV.prototype.getPowerState = function (cb) {
              this.shell('dumpsys power', function (ar) {
                  // var value = ar.join('\r');
                  // var RE_KEYVAL = /^\s*(\S*)=(\S)\r?$/gm;
                  // var properties = {};
                  // var match;
                  // value = value.substr(52);
                  // while (match = RE_KEYVAL.exec(value)) {
                  //     properties[match[1]] = match[2];
                  // }
          
                  var power = lines2Object(ar);
                  var on = power.Display_Power__state;
                  //var i = power.mScreenOn;
                  // power.mSystemReady
                  // power.mDisplayReady;
                  cb && cb(on === 'ON');
              });
          };
          
          FireTV.prototype.getCurrentApp = function (cb) {
              this.shell('dumpsys window windows | grep mCurrentFocus', function (ar) {
                   var value = ar;
                   adapter.log.debug('Shell:' + ar);
                   var RE_APP = /mCurrentFocus=Window{e\d+\s[a-z0-9]+\s(.*)\/(.*)}/gm;
                  // var properties = {};
                   var match;
                  // value = value.substr(52);
                  var currentApp;
                  while (match = RE_APP.exec(value)) {
                          self.dev.setImmediately('currentApp', match[1]);
                          self.dev.setImmediately('currentActivity', match[2]);
                          currentApp = match[1];
                  //     properties[match[1]] = match[2];
                  }
                  cb && cb(currentApp);
              });
          };
          
          function getKeyValue(key) {
              var val = ~~key;
              if (val) return val;
              key = key.replace(/"|'|\s/g, '').toUpperCase();
          
              if ((val = adb.Keycode[key]) !== undefined) return val;
              if ((val = adb.Keycode['KEYCODE_DPAD_' + key]) !== undefined) return val;
              val = adb.Keycode['KEYCODE_' + key];
              return val;
          }
          
          
          function buildInputEvent(key, longpress) {
              key = getKeyValue(key);
              var SEP = ' && ';
              //var SEP = '\n';
              var eventNo = 7;
              var cmd =
                  //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
                  "sendevent /dev/input/event" + eventNo + " 1 " + key + " 1" + SEP +
                  "sendevent /dev/input/event" + eventNo + " 0 0 0" + SEP;
              if (longpress) cmd += 'sleep 1';
              cmd +=
                  //"sendevent /dev/input/event" + eventNo + " 4 4 0007004f" + SEP +
                  "sendevent /dev/input/event" + eventNo + " 1 " + key + " 0" + SEP +
                  "sendevent /dev/input/event" + eventNo + " 0 0 0";
          
              return cmd;
          }
          
          
          var reInputKey = /^[\"|\'](.*)[\"|\']$/;
          
          FireTV.prototype.inputKeyevent = function (val) {
              if (~~val !== 0) return this.shell("input keyevent " + val);
          
              // (4000, 'DOWN', 1000, 'DOWN', 100, 'DOWN', 'RIGHT', 'RIGHT', 'RIGHT', 'RIGHT', 'ENTER', 500, 'DOWN');
              var ar = val.split(',');
              if (ar.length <= 1) ar = val.split(' ');
              var number, i = 0, delay = 0;
              var self = this;
              //self.stopKeyevents
          
              function doIt() {
                  if (i < ar.length && !self.stopKeyevents) {
                      var v = ar[i++].trim();
                      if ((number = ~~v)) {
                          //adapter.log.debug('sendKeys: number, delay=' + v);
                          delay = number;
                          setTimeout (doIt, delay);
                      } else {
                          //adapter.log.debug('sendKeys: ' + v + ' (' + keys[v] + ')');
                          var key;
                          if (reInputKey.test(v)) {
          
                              key = "input text " + normalizeInputText(v.replace(reInputKey, '$1'));
                          } else if (v === 'callback') {
                              self.dev.setImmediately('result', 'callback');
                          } else {
                              key = "input keyevent " + getKeyValue(v);
                          }
                          //console.log('Sending: ' + key + ' i=' + i);
                          self.shell( key, function(lines) {
                              if (i <ar.length && ~~ar[i] > 0) doIt();
                              else setTimeout(doIt, delay);
                          });
                      }
                  }
                  if (self.stopKeyevents) self.stopKeyevents--;
              }
              doIt();
          };
          
          
          FireTV.prototype.frameBuffer = function (val) {
              this.client.framebuffer(this.client.id, 'raw', function(err, stream) {
                  if (err || !stream) return;
                  adb.util.readAll(stream, function(err, output) {
                      err = err;
                  });
              });
          };
          
          function normalizeInputText(t) {
              return t.toString().replace(/\s/g, '%s');
          }
          
          FireTV.prototype.onStateChange = function (channel, state, val) {
              var self = this;
              switch(channel) {
                  case 'framebuffer':
                      this.frameBuffer(val);
                      break;
                  case usedStateNames.shell.n:
                      this.shell(val);
                      break;
                  case usedStateNames.text.n:
                      val = val.replace(/\s/g, '%s');
                      this.shell('input text ' + normalizeInputText(val));
                      break;
                  case 'keys':
                      var code = usedStateNames[state].common.code;
                      this.shell("input keyevent " + code);
                      return true;
                  case usedStateNames.startApp.n:
                      var appPath = knownAppPathes[val.toLowerCase()];
                      if (!appPath) appPath = val;
                      var ar = appPath.split('/');
                      if (ar.length < 2) appPath += '/.MainActivity';
                      this.shell('am start -n ' + appPath);
                      break;
                  case usedStateNames.stopApp.n:
                      var appPath = knownAppPathes[val.toLowerCase()];
                      if (!appPath) appPath = val;
                      var ar = appPath.split('/');
                      this.shell('am force-stop ' + ar[0]);
                      break;
                  case 'sendevent':
                  case usedStateNames.sendKeyCodeArray.n:
                  case usedStateNames.sendKeyCode.n:
                      this.inputKeyevent(val);
                      //this.shell("input keyevent " + val);
                      break;
                  case usedStateNames.reboot.n:
                      this.client.reboot(this.client.id, this.handleCallback.bind(this));
                      break;
                  case usedStateNames.screencap.n:
                      this.client.screencap(this.client.id, this.handleCallback.bind(this));
                      break;
                  case usedStateNames.swapPower.n:
                      this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                      return true;
                  case 'power':
                  case usedStateNames.on.n:
                      this.getPowerState(function(on) {
                          if (val !== on) this.shell("input keyevent " + adb.Keycode.KEYCODE_POWER);
                      }.bind(this));
                      break;
              }
          };
          
          
          function checkIP(cb) {
              if (adapter.config.devices.length) cb && cb();
              cb = undefined;
              var mdns = Mdns({
                  timeout: 4,
                  //returnOnFirstFound: true,
                  name: '_amzn-wplay._tcp.local',
                  find: 'amzn.dmgr:'
              });
              mdns.run (function(res) {
                  res.removeDup('ip', adapter.config.devices);
                  if (!res.length) return cb && cb();
                  soef.changeAdapterConfig(adapter, function(config){
                      res.forEach(function(dev) {
                          if (!config.devices.find(function(v) {
                              return v.ip === dev.ip;
                          })) {
                              config.devices.push({
                                  enabled: true,
                                  name: dev.name,
                                  ip: dev.ip
                              })
                          }
                      });
                      if (config.devices.length !== adapter.config.devices.length) {
                          adapter.config.devices = config.devices;
                          if (cb === undefined) {
                             closeAllFireTVs();
                             startFireTVs();
                          }
                      }
                  }, cb );
              });
          }
          
          
          function checkPATH() {
              var fn, ar = process.env.PATH.split(path.delimiter);
              var exe = isWin ? 'adb.exe' : 'adb';
              ar.find(function(v) {
                  if (v.toLowerCase().indexOf('adb') >= 0) {
                      var _fn = path.join(v, exe);
                      if (soef.existFile(_fn)) {
                          fn = _fn;
                          return true;
                      }
                  }
                  return false;
              });
              return fn;
          }
          
          var defaultMinimalABAndFastboot = 'C:/Program Files (x86)/Minimal ADB and Fastboot/adb.exe';
          function normalizeConfig() {
              var oldAdbPath = adapter.config.adbPath;
              if (!soef.existFile(adapter.config.adbPath)) {
                  if (isWin && adapter.config.adbPath && soef.existFile(adapter.config.adbPath + '.exe')) {
                      adapter.config.adbPath += '.exe';
                  } else {
                      var p = adapter.config.adbPath + '/adb';
                      p = p.replace(/\\/g, '/').replace(/\/\//g, '/');
                      if (!isWin && soef.existFile(p)) {
                          adapter.config.adbPath = p;
                      } else if (isWin && soef.existFile(p + '.exe')) {
                          adapter.config.adbPath = p + '.exe';
                      } else if (isWin && soef.existFile(defaultMinimalABAndFastboot)) {
                          adapter.config.adbPath = defaultMinimalABAndFastboot;
                      } else {
                          adapter.config.adbPath = checkPATH();
                          if (!adapter.config.adbPath) {
                              adapter.log.error('adb executable not found. ' + adapter.config.adbPath);
                              adapter.config.adbPath = 'adb'
                          }
                      }
                  }
                  adapter.config.adbPath = path.normalize(adapter.config.adbPath);
              }
              if (oldAdbPath !== adapter.config.adbPath || adapter.config.devices.unique('ip')) {
                  soef.changeAdapterConfig(adapter, function(config) {
                      config.devices = adapter.config.devices;
                      config.adbPath = adapter.config.adbPath;
                  });
              }
           }
          
          
          function startFireTVs(cb) {
              var i = 0;
              function doIt() {
                  if (i >= adapter.config.devices.length) return cb && cb();
                  var device = adapter.config.devices[i++];
                  if (device.enabled) {
                      var firetv = new FireTV(device);
                      firetv.createStates(doIt);
                  } else {
                      doIt();
                  }
              }
              doIt();
          }
          
          
          function prepareDevices(cb) {
              var re = /^\d*\.\d*\.\d*\.\d*:\d*$/;
              new_g_client();
              g_client.listDevices(function (err, devices) {
                  if (err || !devices) return cb && cb(err);
                  devices.forEach(function (device) {
                      if (!re.test(device.id)) g_client.tcpip(device.id, function (err, port) {
                          if (err || !port) return cb && cb(err);
                          g_client.waitForDevice(device.id, function(err, data) {
                              g_client.getIP(device.id, function(ip) {
                                  if (ip) g_client.connect(ip, port, function(err,data) {
                                      cb && cb(err);
                                  });
                              });
                          });
                      });
                  })
              })
          }
          
          
          function main() {
          
              normalizeConfig();
              prepareDevices();
          
              soef.deleteOrphanedDevices('ip', adapter.config.devices);
              checkIP(function () {
                  startFireTVs(function () {
                      trackDevices();
                  })
              });
          
              adapter.subscribeStates('*');
              //adapter.subscribeObjects('*');
          }
          
          
          J Offline
          J Offline
          jens1987
          schrieb am zuletzt editiert von
          #4

          @HenryH Morgen darf ich fragen wie du es geschafft hast. Finde keine Anleitung dazu. Habe ein Firetv Cube. Iobroker läuft auf einer Synology im Docker. Danke

          1 Antwort Letzte Antwort
          0
          Antworten
          • In einem neuen Thema antworten
          Anmelden zum Antworten
          • Älteste zuerst
          • Neuste zuerst
          • Meiste Stimmen


          Support us

          ioBroker
          Community Adapters
          Donate

          702

          Online

          32.6k

          Benutzer

          82.0k

          Themen

          1.3m

          Beiträge
          Community
          Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
          ioBroker Community 2014-2025
          logo
          • Anmelden

          • Du hast noch kein Konto? Registrieren

          • Anmelden oder registrieren, um zu suchen
          • Erster Beitrag
            Letzter Beitrag
          0
          • Home
          • Aktuell
          • Tags
          • Ungelesen 0
          • Kategorien
          • Unreplied
          • Beliebt
          • GitHub
          • Docu
          • Hilfe