简体   繁体   English

Phoenix Channel从项目外部的客户端发送消息

[英]Phoenix Channel sending messages from a client outside the project

I wanted to send a message to my user channel of my Phoenix Application. 我想向我的Phoenix应用程序的用户通道发送一条消息。 I have joined a user_token with the channel as users:user_token in the user_channel.ex . 我已经在user_channel.exusers:user_token身份加入了该频道的users:user_token I was successful doing it from another controller called the toy_controller by calling a broadcast method. 我通过调用广播方法从另一个名为toy_controller的控制器成功完成了此操作。 The broadcast method is in the user channel. 广播方法在用户频道中。 And I have written a jQuery file to handle the events. 而且我已经编写了一个jQuery文件来处理事件。 I was looking for something which can send messages to the same channel from outside of the project, because I wanted to do some IoT stuff. 我一直在寻找可以从项目外部将消息发送到同一通道的消息,因为我想做一些物联网工作。 I have tried a python module called occamy.socket and the JS client of Phoenix that it uses internally. 我尝试了一个名为occamy.socket的python模块,以及内部使用的Phoenix的JS客户端。 Then, I found a disconnection always. 然后,我总是发现断开连接。 I can't figure out the exact address of the websocket connection from Phoenix. 我无法弄清楚Phoenix的websocket连接的确切地址。 If I am trying it with that Phoenix npm library in that project folder itself, it says ReferenceError: window is not defined always. 如果我使用该项目文件夹本身中的Phoenix npm库进行尝试,它会显示ReferenceError: window is not defined始终ReferenceError: window is not defined And, I think it is because of the initialization part of the socket in the web/static/js/socket.js file where it's written as 而且,我认为这是因为web/static/js/socket.js文件中套接字的初始化部分写为

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

, but I am not sure. ,但我不确定。 The thing that I have tried is below 我尝试过的东西如下

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

In the python client, I was also trying to connect to this address and got a disconnection error. 在python客户端中,我也试图连接到该地址,并收到断开连接错误。 I want to do it for IoT purposes, where I want to monitor sensor data of a user. 我想将其用于物联网目的,即要监视用户的传感器数据。 Each user will be having their own sensors to be monitored. 每个用户将拥有自己的传感器进行监视。 So, I have configured the channel topic:subtopic channel as users:user_token . 因此,我已经将channel topic:subtopic channel配置为users:user_token I need to send messages from my raspberry pi to this channel using those unique tokens of the users. 我需要使用用户的唯一令牌将树莓派的消息发送到此通道。 My user_channel, user.js, app.js and socket.js are given below. 我的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 // 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 => { console.log("Change:", toy); $("#message").append(toy["name"]) }) } }); 

Finally, I am able to send and receive messages asynchronously from a python program. 最后,我能够从python程序异步发送和接收消息。 It uses websockets asyncio module from python. 它使用python的websockets asyncio模块。 I figured out the various events required for phoenix channels like 'phx_join' for joining a topic and all. 我弄清楚了诸如“ phx_join”之类的凤凰频道加入主题所需的各种事件。 So, the following program worked. 因此,以下程序起作用了。

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM