TypeError: PythonShell is not a constructor

TypeError: PythonShell is not a constructor

我正在试验 node red - VOLTTRON(Python 框架)integration 我希望在 Node Red 中查看 VOLTTRON 消息总线。

当我执行 README 中定义的适当步骤时,例如将文件复制到正确的 ~/.node-red/nodes/volttron 并获取正确的 VOLTTRON 身份验证密钥

当我启动 Node Red 时,出现错误:

12 Dec 14:07:54 - [info] Server now running at http://127.0.0.1:8000/
12 Dec 14:07:54 - [info] Starting flows
12 Dec 14:07:54 - [info] Started flows
12 Dec 14:07:54 - [warn] [volttron-input:03074cce8abc3174] /home/ben/.node-red/nodes/volttron
12 Dec 14:07:54 - [warn] [volttron-input:03074cce8abc3174] /home/ben/.node-red/nodes/volttron/node_red_subscriber.py
12 Dec 14:07:54 - [red] Uncaught Exception:
12 Dec 14:07:54 - TypeError: PythonShell is not a constructor
    at Timeout._onTimeout (/home/ben/.node-red/nodes/volttron/volttron.js:33:23)
    at listOnTimeout (internal/timers.js:554:17)
    at processTimers (internal/timers.js:497:7)

我不确定这是否是与 javascript 或 Python 相关的问题?感谢您提供零智慧旁边的任何提示。

volttron.js

module.exports = function(RED) {
    // Set these variables to be valid file paths
    var volttron_env = '/home/ben/.volttron';
    var volttron_home = '/home/ben/Desktop/volttron';
    var python_path = '/usr/lib/python3.8';

    function VolttronInputNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        var pyshell = null;
        this.on('close', function(done) {
            setTimeout(function() {
                /* do some asynchronous cleanup before calling done */
                if (pyshell && !pyshell.terminated && pyshell.childProcess)
                    pyshell.childProcess.kill('SIGINT');
                done();
            });
        });
        setTimeout(function() {
            var PythonShell = require('python-shell');
            process.env['VIRTUAL_ENV'] = volttron_env;
            process.env['VOLTTRON_HOME'] = volttron_home;
            var options = {
                mode: 'json',
                pythonPath: python_path,
                scriptPath: __dirname,
            };
            var path = require('path');
            node.warn(__dirname);
            var scriptName = 'node_red_subscriber.py';
            var scriptPath = path.resolve(__dirname, scriptName);
            node.warn(scriptPath);
            pyshell = new PythonShell(scriptName, options);

            pyshell.on('message', function (data) {
                msg = {};
                msg.topic = node.name;
                msg.payload = data;
                node.send(msg);
            });

            pyshell.end(function (err) {
                node.error(err);
            });

        });
    }
    RED.nodes.registerType("volttron-input", VolttronInputNode);

    function VolttronOutputNode(config) {
        RED.nodes.createNode(this,config);
        var node = this;
        this.on('close', function(done) {
            setTimeout(function() { /* do some asynchronous cleanup before calling done */ done(); });
        });
        this.on("input", function (msg) {
            setTimeout(function() { // send asynchronously
                var PythonShell = require('python-shell');
                process.env['VIRTUAL_ENV'] = volttron_env;
                process.env['VOLTTRON_HOME'] = volttron_home;
                var options = {
                    mode: 'json',
                    pythonPath: python_path,
                    scriptPath: __dirname,
                    args: [msg.payload.topic, msg.payload.data]
                };
                var path = require('path');
                var scriptName = 'node_red_publisher.py';
                var scriptPath = path.resolve(__dirname, scriptName);
                PythonShell.run(scriptName, options, function(err, result) {
                    if (err) node.error(err);
                    if (result) node.warn(result);
                });
            });

        });
    }
    RED.nodes.registerType("volttron-output",VolttronOutputNode);

}

node_red_subscriber.py

from datetime import datetime
import os
import sys


import gevent

from volttron.platform.messaging import headers as headers_mod
from volttron.platform.vip.agent import Agent, PubSub, Core
from volttron.platform.agent import utils
from volttron.platform.scheduling import periodic
from volttron.platform import jsonapi

from settings import topic_prefixes_to_watch, heartbeat_period, agent_kwargs


class NodeRedSubscriber(Agent):

    def onmessage(self, peer, sender, bus, topic, headers, message):
        d = {'topic': topic,
             'headers': headers,
             'message': message}
        sys.stdout.write(jsonapi.dumps(d)+'\n')
        sys.stdout.flush()

    @Core.receiver('onstart')
    def onstart(self, sender, **kwargs):
        for prefix in topic_prefixes_to_watch:
            self.vip.pubsub.subscribe(peer='pubsub', prefix=prefix, callback=self.onmessage).get(timeout=10)

    # Demonstrate periodic decorator and settings access
    @Core.schedule(periodic(heartbeat_period))
    def publish_heartbeat(self):
        now = utils.format_timestamp(datetime.utcnow())
        headers = {
            headers_mod.CONTENT_TYPE: headers_mod.CONTENT_TYPE.PLAIN_TEXT,
            headers_mod.DATE: now,
            headers_mod.TIMESTAMP: now
        }
        result = self.vip.pubsub.publish('pubsub', 'heartbeat/NodeRedSubscriber', headers, now)
        result.get(timeout=10)


if  __name__ == '__main__':
    try:
        # If stdout is a pipe, re-open it line buffered
        if utils.isapipe(sys.stdout):
            # Hold a reference to the previous file object so it doesn't
            # get garbage collected and close the underlying descriptor.
            stdout = sys.stdout
            sys.stdout = os.fdopen(stdout.fileno(), 'w', 1)

        agent = NodeRedSubscriber(identity='NodeRedSubscriber', **agent_kwargs)
        task = gevent.spawn(agent.core.run)

        try:
            task.join()
        finally:
            task.kill()

    except KeyboardInterrupt:
        pass

编辑 进一步尝试一些步骤,在目录 .node-red/node_modules 中,我放置了一个名为 package.json 的文件,其中包含答案中提供的内容以及答案中提供的依赖项 "python-shell": "^1.0.4"。然后从 bash 的同一目录 运行 出现一些 npm 错误:

~/.node-red/node_modules$ npm install volttron

回溯:

npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/volttron - Not found
npm ERR! 404
npm ERR! 404  'volttron@*' is not in this registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/ben/.npm/_logs/2021-12-13T12_52_57_550Z-debug.log

在其他目录中~/.node-red/nodes/volttron

存在这些文件:

node_red_publisher.py  node_red_subscriber.py  README  settings.py  volttron.html  volttron.js

在之前的中,我不得不猜测节点使用的是哪个版本的python-shell,因为它没有任何提示,所以我选择了当前的最新版本(3.0.1)作为任意选择。

看来这是错误的选择,所以我建议您再次编辑 package.json 文件并将 python-shell 依赖项的 ^3.0.1 版本更改为 ^1.0.4

{
    "name"         : "volttron",
    "version"      : "0.0.1",
    "description"  : "A sample node for node-red",
    "dependencies": {
        "python-shell": "^1.0.4"
    },
    "keywords": [ "node-red" ],
    "node-red"     : {
        "nodes": {
            "volttron": "volttron.js"
        }
    }
}

您需要在 volttron 目录中进行更改后再次 运行 npm install

如果不是这种情况,那么您将不得不与 Volttron 联系。