1

我想发送一条消息给我的Phoenix应用程序的用户频道。我加入了user_channel.ex中的频道为users:user_token的user_token。我通过调用广播方法从另一个名为toy_controller的控制器成功完成。广播方法在用户频道中。我写了一个jQuery文件来处理事件。我一直在寻找可以从项目之外向同一频道发送消息的东西,因为我想做一些物联网的东西。我已经尝试了一个名为occamy.socket的python模块以及它在内部使用的Phoenix的JS客户端。然后,我总是发现断开连接。我无法弄清凤凰网络连接的确切地址。如果我正在使用该项目文件夹中的Phoenix npm库,它总是说ReferenceError: window is not defined。而且,我认为这是因为在web/static/js/socket.js文件插座的初始化部分的地方它写成菲尼克斯频道发送来自项目外客户的消息

let socket = new Socket("/socket", {params: {token: window.userToken}})        

,但我不知道。我试过的东西是

var Socket = require("phoenix-socket").Socket; 
var socket = new Socket("ws://localhost:4000/socket"); 

在python客户端,我也试图连接到这个地址,并得到了断开连接错误。我想为了IoT的目的而做它,我想监视用户的传感器数据。每个用户都将拥有自己的传感器进行监控。因此,我已将频道topic:subtopic频道配置为users:user_token。我需要使用用户的这些独特的令牌从我的树莓派发送消息到这个频道。下面给出了我的user_channel,user.js,app.js和socket.js。

//web/static/js/socket.js 
 
import {Socket} from "phoenix" 
 

 
let socket = new Socket("/socket", {params: {token: window.userToken}}) 
 

 

 
socket.connect() 
 

 

 
export default socket

//web/static/app.js 
 

 

 
import "phoenix_html" 
 
import user from "./user"

#web/channels/user_channel.ex 
defmodule Tworit.UserChannel do 
    use Tworit.Web, :channel 

    def join("users:" <> user_token, payload, socket) do 
     if authorized?(payload) do 
      {:ok, "Joined To User:#{user_token}", socket} 
     else 
      {:error, %{reason: "unauthorized"}} 
     end 
    end 


    def handle_in("ping", payload, socket) do 
     {:reply, {:ok, payload}, socket} 
    end 


    def handle_in("shout", payload, socket) do 
     broadcast socket, "shout", payload 
     {:noreply, socket} 
    end 


    def handle_out(event, payload, socket) do 
     push socket, event, payload 
     {:noreply, socket} 
    end 


    defp authorized?(_payload) do 
     true 
    end 

    def broadcast_change(toy, current_user) do 
     payload = %{ 
     "name" => toy.name, 
     "body" => toy.body 
     } 
     Tworit.Endpoint.broadcast("users:#{current_user.token}", "change", payload) 
    end 

end 

//web/static/js/user.js 
 
import socket from "./socket" 
 

 
$(function() { 
 
    let ul = $("ul#em") 
 

 
    if (ul.length) { 
 
    var token = ul.data("id") 
 
    var topic = "users:" + token 
 
\t \t 
 
    // Join the topic 
 
    let channel = socket.channel(topic, {}) 
 
    channel.join() 
 
     .receive("ok", data => { 
 
     console.log("Joined topic", topic) 
 
     }) 
 
     .receive("error", resp => { 
 
     console.log("Unable to join topic", topic) 
 
     }) 
 
    channel.on("change", toy => { 
 
\t  console.log("Change:", toy); 
 
\t  $("#message").append(toy["name"]) 
 
    }) 
 
    } 
 
});

回答

0

最后,我能够从python程序异步发送和接收消息。它使用python的websockets asyncio模块。我想出了凤凰频道所需的各种事件,如“phx_join”,以加入主题和所有内容。所以,下面的程序工作。

import asyncio 
import websockets 
import json 
import time 
from random import randint 
import serial 

from pyfirmata import Arduino, util 

board = Arduino('/dev/ttyACM1') 

it = util.Iterator(board) 
it.start() 
board.analog[0].enable_reporting() 
board.analog[1].enable_reporting() 
board.analog[2].enable_reporting() 
board.analog[3].enable_reporting() 

import RPi.GPIO as gpio 

gpio.setmode(gpio.BCM) 
gpio.setup(14, gpio.OUT) 


async def main(): 
    async with websockets.connect('ws://IP_addr:4000/socket/websocket') as websocket: 
     data = dict(topic="users:user_token", event="phx_join", payload={}, ref=None) 
     #this method joins the phoenix channel 
     await websocket.send(json.dumps(data)) 

     print("Joined") 

     while True: 
      msg = await retrieve() # waits for data from arduino analog pins 
      await websocket.send(json.dumps(msg)) # sends the sensor output to phoenix channel 

      print("sent") 
      call = await websocket.recv() # waits for anything from the phoenix server 
      control = json.loads(call) 

      # I have sent values from 2 buttons for swicthing a led with event 'control' 

      if(control['event'] == "control"): 
       event(control['payload']['val']) #swiches the led as per the input from event 'control' 


      print("< {}".format(call)) 

def event(val): 
    if(val == "on"): 
     gpio.output(14, True) 
    if(val == "off"): 
     gpio.output(14, False) 

async def retrieve(): 
    #analog read 
    load = board.analog[0].read() 
    pf = board.analog[1].read() 
    reading = board.analog[2].read() 
    thd = board.analog[3].read() 
    output = {"load": load, "pf": pf, "reading": reading,"thd": thd} 

    msg = dict(topic="users:user_token", event="sensor_output", payload=output, ref=None) # with 
    #event "sensor_outputs" 
    #the phoenix server displays the data on to a page. 

    print(msg) 
    return(msg) 

asyncio.get_event_loop().run_until_complete(main()) 
asyncio.get_event_loop().run_forever()