mrusme / kiwi

Pimoroni Keybow based, WiFi-enabled Macro Pad (a.k.a. poor-man's Elgato Stream Deck)
https://マリウス.com/kiwi-a-nerves-based-firmware-for-the-pimoroni-keybow/
GNU General Public License v3.0
61 stars 6 forks source link

Application kiwi exited: exited in: Kiwi.Application.start(:normal, []) #2

Open SirMaple opened 2 years ago

SirMaple commented 2 years ago

First off this is awesome! I'm hoping to use Kiwi on my PIM420 in order to control some tasmota switches and other items in my home.

I'm not able to get any response using curl. I can ping and ssh into the Pi using the provided ssh key(took a bit for me to figure that part out since it's not mentioned that the key in the repo must be used).

I only thing that stands out in the RingLogger.next output is:

21:40:12.842 [debug] Restarted Erlang distribution as node :"kiwi@nerves.local"

21:40:13.161 [debug] Mnesiahack: Schema initialized, at least if it wasn't there before.

21:40:14.620 [debug] Mnesiahack: Mnesia started.

21:40:15.622 [debug] Mnesiahack: All done.

21:40:15.762 [info]  Application kiwi exited: exited in: Kiwi.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (FunctionClauseError) no function clause matching in Kiwi.Application.children/2
            (kiwi 1.0.2) lib/kiwi/application.ex:54: Kiwi.Application.children(:rpi0, %{KEY_MGMT: "WPA-PSK", PSK: "PASSWORD HERE", SSID: "HOME_CONTROL"})
            (kiwi 1.0.2) lib/kiwi/application.ex:14: Kiwi.Application.start/2
            (kernel 7.3) application_master.erl:277: :application_master.start_it_old/4

21:40:15.827 [info]  Application mojito exited: :stopped

21:40:15.828 [info]  Application poolboy exited: :stopped

21:40:15.829 [info]  Application castore exited: :stopped

21:40:15.840 [info]  Application mint exited: :stopped

21:40:15.841 [info]  Application corsica exited: :stopped

21:40:15.842 [info]  Application jason exited: :stopped

21:40:15.853 [info]  Application plug_cowboy exited: :stopped

21:40:15.854 [info]  Application cowboy_telemetry exited: :stopped

21:40:15.856 [info]  Application maru exited: :stopped

21:40:15.866 [info]  Application plug exited: :stopped

21:40:15.877 [info]  Application telemetry exited: :stopped

21:40:15.887 [info]  Application plug_crypto exited: :stopped

21:40:15.898 [info]  Application mime exited: :stopped

21:40:15.899 [info]  Application eex exited: :stopped

21:40:15.909 [info]  Application cowboy exited: :stopped

21:40:15.910 [info]  Application cowlib exited: :stopped

21:40:15.921 [info]  Application ranch exited: :stopped

21:40:15.922 [info]  Application circuits_i2c exited: :stopped

21:40:15.923 [info]  Application circuits_spi exited: :stopped

21:40:15.924 [info]  Application circuits_gpio exited: :stopped

21:40:15.925 [info]  Application toolshed exited: :stopped

21:40:15.936 [info]  Application websockex exited: :stopped

21:40:15.983 [info]  Application mnesia exited: :stopped

I've also attached a full copy of the output of RingLogger.next. I did remove my PSK and replace it with "PASSWORD HERE" but we know the issue is not wifi since I can ssh in so that shouldn't be an issue.

Any help would be greatly appreciated log.txt !

mrusme commented 2 years ago

Did you enable the OBS endpoint?

//Edit: Maybe you can paste your configuration with blanked out password/ssid here?

SirMaple commented 2 years ago

I did not enable the OBS endpoint and removed the line as suggested in the Installation section.

Contents of kiwi.txt:

user@macbookair-wired-dock BOOT-A % cat kiwi.txt 
NERVES_NETWORK_KEY_MGMT=WPA-PSK
NERVES_NETWORK_SSID=HOME_CONTROL
NERVES_NETWORK_PSK=PASSWORD HERE
user@macbookair-wired-dock BOOT-A %
mrusme commented 2 years ago

Could you try enabling it and see if it works then?

SirMaple commented 2 years ago

So made some progress.

I added NERVES_NETWORK_OBS_SOCKET=ws://obs.lan:4444 to kiwi.txt:

user@macbookair-wired-dock BOOT-A % cat kiwi.txt
NERVES_NETWORK_KEY_MGMT=WPA-PSK
NERVES_NETWORK_SSID=HOME_CONTROL
NERVES_NETWORK_PSK=PASSWORD HERE
NERVES_NETWORK_OBS_SOCKET=ws://obs.lan:4444
user@macbookair-wired-dock BOOT-A %

I still get an error, but now the gpios are seen in the RingLogger.next output. Full output attached.

New error:

17:37:00.328 [info]  Application kiwi exited: Kiwi.Application.start(:normal, []) returned an error: shutdown: failed to start child: Kiwi.OBS
    ** (EXIT) %WebSockex.ConnError{original: :nxdomain}

I was hoping to use this without OBS. Is that not possible?

log1.txt

mrusme commented 2 years ago

Yes, it should be possible and I believe to have found the issue. Will work on a fix asap.

If you want to use it right now it's probably best to just set up any websocket on that address. As long as it can connect to it, it should be good.

SirMaple commented 2 years ago

So I added one of my internal web servers(port 81 is correct) to the kiwi.txt:

user@macbookair-wired-dock BOOT-A % cat kiwi.txt
NERVES_NETWORK_KEY_MGMT=WPA-PSK
NERVES_NETWORK_SSID=HOME_CONTROL
NERVES_NETWORK_PSK=PASSWORD HERE
NERVES_NETWORK_OBS_SOCKET=ws://192.168.0.147:81
user@macbookair-wired-dock BOOT-A %

I still get an error in the RingLogger.next output:

19:03:58.409 [info]  Application kiwi exited: Kiwi.Application.start(:normal, []) returned an error: shutdown: failed to start child: Kiwi.OBS
    ** (EXIT) %WebSockex.RequestError{code: 200, message: "OK"}

Full log attached.

log2.txt

SirMaple commented 2 years ago

So I've got this working to the point it now responds in a web browser. But I'm not able to POST anything using curl.

Current kiwi.txt:

user@macbookair-wired-dock BOOT-A % cat kiwi.txt
NERVES_NETWORK_KEY_MGMT=WPA-PSK
NERVES_NETWORK_SSID=HOME_CONTROL
NERVES_NETWORK_PSK=PASSWORD HERE
NERVES_NETWORK_OBS_SOCKET=ws://192.168.0.147:8010
user@macbookair-wired-dock BOOT-A %

Fixed it to actually use a websocket by setting up a websocket test sever in docker.

GET /settings result:

user@macbookair-wired-dock ~ % curl "http://192.168.33.116:8080/settings" \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{}'
{"content":{"param":"settings","reason":"required"},"timestamp":"2022-02-25 22:41:39.267703Z"}%                                                        >user@macbookair-wired-dock ~ % 

HTTP Action:

user@macbookair-wired-dock ~ % curl -X POST "http://192.168.33.116:8080/settings/keys/key_1_in_row_1" \
    -H "Content-Type: application/json; charset=utf-8" \
    -d $'{
          "object": {
            "keydown": {
              "http": [
                {
                  "body": "{}",
                  "method": "post",
                  "headers": {
                    "content-type": "application/json"
                  },
                  "url": "http://192.168.33.133/cm?cmnd=Power%20TOGGLE"
                }
              ]
            }
          }
        }'
{"content":null,"timestamp":"2022-02-25 22:46:31.630382Z"}%
user@macbookair-wired-dock ~ %       

Result seen in RingLogger.next:

iex(kiwi@nerves.local)12> RingLogger.next

22:46:31.624 [info]  POST /settings/keys/key_1_in_row_1

22:46:31.629 [error] {:aborted, {:no_exists, Kiwi.Collection.Setting}}

22:46:31.631 [info]  Sent 500 in 6ms

3 out of 3 new messages shown.
:ok
iex(kiwi@nerves.local)13> 

I then press key_1_in_row_1 and the following is shown in RingerLogger.next:

iex(kiwi@nerves.local)14> RingLogger.next

22:50:37.399 [debug] Handle Info

22:50:37.399 [debug] {:circuits_gpio, 20, 1228619885061, 0}

22:50:37.403 [debug] %{gpios: [#Reference<0.2322064396.268828676.223988>, #Reference<0.2322064396.268828676.223989>, #Reference<0.2322064396.268828676.223990>, #Reference<0.2322064396.268828676.223991>, #Reference<0.2322064396.268828676.223992>, #Reference<0.2322064396.268828676.223993>, #Reference<0.2322064396.268828676.223994>, #Reference<0.2322064396.268828676.223995>, #Reference<0.2322064396.268828676.223996>, #Reference<0.2322064396.268828676.223997>, #Reference<0.2322064396.268828676.223998>, #Reference<0.2322064396.268828676.223999>], key_1_in_row_1: 17, key_1_in_row_2: 15, key_1_in_row_3: 9, key_1_in_row_4: 9, key_2_in_row_1: 11, key_2_in_row_2: 5, key_2_in_row_3: 5, key_2_in_row_4: 7, key_3_in_row_1: 15, key_3_in_row_2: 7, key_3_in_row_3: 5, key_3_in_row_4: 7, ledarray: %Kiwi.LedArray{led_array: [0, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, ...], ref: #Reference<0.2322064396.268828676.224003>}}

22:50:37.403 [debug] Keydown for pin 20

22:50:37.405 [info]  No key action defined for key_1_in_row_1!

22:50:37.510 [debug] Handle Info

22:50:37.510 [debug] {:circuits_gpio, 20, 1228730816300, 1}

22:50:37.515 [debug] %{gpios: [#Reference<0.2322064396.268828676.223988>, #Reference<0.2322064396.268828676.223989>, #Reference<0.2322064396.268828676.223990>, #Reference<0.2322064396.268828676.223991>, #Reference<0.2322064396.268828676.223992>, #Reference<0.2322064396.268828676.223993>, #Reference<0.2322064396.268828676.223994>, #Reference<0.2322064396.268828676.223995>, #Reference<0.2322064396.268828676.223996>, #Reference<0.2322064396.268828676.223997>, #Reference<0.2322064396.268828676.223998>, #Reference<0.2322064396.268828676.223999>], key_1_in_row_1: 18, key_1_in_row_2: 15, key_1_in_row_3: 9, key_1_in_row_4: 9, key_2_in_row_1: 11, key_2_in_row_2: 5, key_2_in_row_3: 5, key_2_in_row_4: 7, key_3_in_row_1: 15, key_3_in_row_2: 7, key_3_in_row_3: 5, key_3_in_row_4: 7, ledarray: %Kiwi.LedArray{led_array: [0, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, 0, 227, 0, 0, ...], ref: #Reference<0.2322064396.268828676.224003>}}

22:50:37.515 [debug] Keyup for pin 20

22:50:37.517 [info]  No key action defined for key_1_in_row_1!

10 out of 10 new messages shown.
:ok
iex(kiwi@nerves.local)15>
mrusme commented 2 years ago

Can you give the bulk POST a try, as documented here? Your POST actually looks fine, but the response you retrieve doesn't look good.

SirMaple commented 2 years ago

Still getting errors.

POST:

curl -X "POST" "http://192.168.33.116:8080/settings" \
    -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
          "settings": [
            {
              "id": "key_1_in_row_1",
              "object": {
                "keydown": {
                  "http": [
                 {
                       "body": "{}",
                    "method": "post",
                        "headers": {
                     "content-type": "application/json"
                      },
                          "url": "http://192.168.33.129/cm?cmnd=Power%20TOGGLE"
                   }
                  ]
                }
              }
            }
        }'

Output of RingLogger.next:

iex(kiwi@nerves.local)4> RingLogger.next
21:34:06.863 [info]  POST /settings

21:34:06.868 [error] %Plug.Parsers.ParseError{exception: %Jason.DecodeError{data: "{\n          \"settings\": [\n            {\n              \"id\": \"key_1_in_row_1\",\n              \"object\": {\n                \"keydown\": {\n                  \"http\": [\n                 {\n                       \"body\": \"{}\",\n                    \"method\": \"post\",\n                        \"headers\": {\n                     \"content-type\": \"application/json\"\n                      },\n                          \"url\": \"http://192.168.33.129/cm?cmnd=Power%20TOGGLE\"\n                   }\n                  ]\n                }\n              }\n            }\n        }", position: 550, token: nil}, plug_status: 400}

21:34:06.871 [error] #PID<0.548.0> running Kiwi.Api (connection #PID<0.547.0>, stream id 1) terminated
Server: 192.168.33.116:8080 (http)
Request: POST /settings
** (exit) an exception was raised:
    ** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for %Plug.Parsers.ParseError{exception: %Jason.DecodeError{data: "{\n          \"settings\": [\n            {\n              \"id\": \"key_1_in_row_1\",\n              \"object\": {\n                \"keydown\": {\n                  \"http\": [\n                 {\n                       \"body\": \"{}\",\n                    \"method\": \"post\",\n                        \"headers\": {\n                     \"content-type\": \"application/json\"\n                      },\n                          \"url\": \"http://192.168.33.129/cm?cmnd=Power%20TOGGLE\"\n                   }\n                  ]\n                }\n              }\n            }\n        }", position: 550, token: nil}, plug_status: 400} of type Plug.Parsers.ParseError (a struct), Jason.Encoder protocol must always be explicitly implemented.

If you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:

    @derive {Jason.Encoder, only: [....]}
    defstruct ...

It is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:

    @derive Jason.Encoder
    defstruct ...

Finally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:

    Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])
    Protocol.derive(Jason.Encoder, NameOfTheStruct)
. This protocol is implemented for the following type(s): Kiwi.Collection.Setting, Kiwi.Collection.Led, NaiveDateTime, Atom, DateTime, BitString, Map, Decimal, Date, Any, Jason.Fragment, Integer, Float, List, Time
        (jason 1.2.2) lib/jason.ex:199: Jason.encode_to_iodata!/2
        (kiwi 1.0.2) lib/kiwi/helpers/response.ex:29: Kiwi.Helpers.Response.resp_json/2
        (plug_cowboy 2.5.0) lib/plug/cowboy/handler.ex:12: Plug.Cowboy.Handler.init/2
        (cowboy 2.9.0) /home/runner/work/kiwi/kiwi/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
        (cowboy 2.9.0) /home/runner/work/kiwi/kiwi/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
        (cowboy 2.9.0) /home/runner/work/kiwi/kiwi/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
        (stdlib 3.14.1) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

3 out of 3 new messages shown.
:ok
iex(kiwi@nerves.local)5>

Text file of output -> RingLogger.txt

Just a thought. Is there any way to make a config file and place it on the SD card instead of using curl?

mrusme commented 2 years ago

I've validated the JSON you're posting here and found out you're missing a ] at the end. This is valid json:

{
    "settings": [{
        "id": "key_1_in_row_1",
        "object": {
            "keydown": {
                "http": [{
                    "body": "{}",
                    "method": "post",
                    "headers": {
                        "content-type": "application/json"
                    },
                    "url": "http://192.168.33.129/cm?cmnd=Power%20TOGGLE"
                }]
            }
        }
    }]
}

Please re-try with this.

SirMaple commented 2 years ago

I gave that a try on a linux machine this time and got the following:

root@ironhide:~# curl -X "POST" "http://192.168.33.116:8080/settings"
'{
                "settings": [{
                "id": "key_1_in_row_1",
                "object": {
                        "keydown": {
                                "http": [{
                                        "body": "{}",
                                        "method": "post",
                                        "headers": {
                                                "content-type": "application/json"
                                        },
                                        "url": "http://192.168.33.129/cm?cmnd=Power%20TOGGLE"
                                }]
                        }
                }
        }]
}'
{"content":{"param":"settings","reason":"required"},"timestamp":"2022-03-01 21:09:51.673505Z"}-bash: {
                "settings": [{
                "id": "key_1_in_row_1",
                "object": {
                        "keydown": {
                                "http": [{
                                        "body": "{}",
                                        "method": "post",
                                        "headers": {
                                                "content-type": "application/json"
                                        },
                                        "url": "http://192.168.33.129/cm?cmnd=Power%20TOGGLE"
                                }]
                        }
                }
        }]
}: File name too long
root@ironhide:~# 

RingLogger.next:

iex(kiwi@nerves.local)4> RingLogger.next

21:09:51.668 [info]  POST /settings

21:09:51.673 [error] %Maru.Exceptions.InvalidFormat{param: :settings, plug_status: 400, reason: :required, value: nil}

21:09:51.674 [info]  Sent 400 in 4ms

3 out of 3 new messages shown.
:ok
iex(kiwi@nerves.local)5> 

So I'm not sure what's happening.

mrusme commented 2 years ago

Thanks for all the great feedback, I will investigate this!

SirMaple commented 2 years ago

Any update on this? Need anything further from me?

mrusme commented 2 years ago

@SirMaple no info needed, sorry, I just haven't had time to dig into it.