diff --git a/package/gluon-announce/Makefile b/package/gluon-announce/Makefile
index 3f62c88950672c3dc438efec6ffb392e07b099ed..d2742cf7fb08be2ab4f4eab8d33563432b4eda17 100644
--- a/package/gluon-announce/Makefile
+++ b/package/gluon-announce/Makefile
@@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/package.mk
 define Package/gluon-announce
   SECTION:=gluon
   CATEGORY:=Gluon
-  DEPENDS:=+gluon-core +luci-lib-json +lua-ethtool-stats
+  DEPENDS:=+gluon-core +luci-lib-jsonc +lua-ethtool-stats
   TITLE:=Lua scripts announcing various information
 endef
 
diff --git a/package/gluon-announce/files/lib/gluon/announce/collect.lua b/package/gluon-announce/files/lib/gluon/announce/collect.lua
index e2974b4988994e7bfb87cb2fc19a426f0dada3ab..4339207523590e2928ac8f2b9c33a3c66a42d45b 100755
--- a/package/gluon-announce/files/lib/gluon/announce/collect.lua
+++ b/package/gluon-announce/files/lib/gluon/announce/collect.lua
@@ -1,10 +1,9 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local ltn12 = require 'luci.ltn12'
 
 local announce_dir = '/lib/gluon/announce/' .. arg[1] .. '.d'
 
-encoder = json.Encoder(announce.collect_dir(announce_dir))
-ltn12.pump.all(encoder:source(), ltn12.sink.file(io.stdout))
+print(json.stringify(announce.collect_dir(announce_dir)))
diff --git a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
index be855b3aac95d6081e57f10fbefdd725dc3456a2..fdd2479e0872cc4a7e35b5aabadc3ade198297e0 100644
--- a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
+++ b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua
@@ -3,7 +3,6 @@
 module('gluon.announce', package.seeall)
 
 fs = require 'nixio.fs'
-json = require 'luci.json'
 uci = require('luci.model.uci').cursor()
 util = require 'luci.util'
 
@@ -16,7 +15,7 @@ local function collect_entry(entry)
 end
 
 function collect_dir(dir)
-	local ret = { [json.null] = true }
+	local ret = { [{}] = true }
 
 	for entry in fs.dir(dir) do
 		if entry:sub(1, 1) ~= '.' then
diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
index 99116b81affc42ac82ab007d1a813f8ed1cdfbb2..a9de80e63f1eb33d7447129bbea02c61e65011d1 100644
--- a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
+++ b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua
@@ -1,6 +1,6 @@
 local announce = require 'gluon.announce'
 local deflate = require 'deflate'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 
 
 local function collect(type)
@@ -12,7 +12,7 @@ module('gluon.announced', package.seeall)
 
 function handle_request(query)
   if query:match('^nodeinfo$') then
-    return json.encode(collect('nodeinfo'))
+    return json.stringify(collect('nodeinfo'))
   end
 
   local m = query:match('^GET ([a-z ]+)$')
@@ -27,7 +27,7 @@ function handle_request(query)
     end
 
     if next(data) then
-      return deflate.compress(json.encode(data))
+      return deflate.compress(json.stringify(data))
     end
   end
 end
diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
index cfdd72dc69df8d9a0655d7f046ee5b2c6eefb46b..e83f188f4c67ded5c07479da758404a20515b25c 100644
--- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
+++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv
@@ -22,7 +22,7 @@ function batadv()
     if mac1 ~= nil and mac1 == mac2 then
       ifaddress = ifname2address(ifname)
       if interfaces[ifaddress] == nil then
-        interfaces[ifaddress] = { neighbours = { [json.null] = true } }
+        interfaces[ifaddress] = { neighbours = { [{}] = true } }
       end
 
       interfaces[ifaddress].neighbours[mac1] = { tq = tonumber(tq)
diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
index e0c3c9acd24fefd4fa9196c086eb6ed8d67c753d..1ac22d30cfb4eb76517eeed8650ed1fb90ed39a2 100644
--- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
+++ b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces
@@ -49,5 +49,5 @@ return {
   wireless = nil_table(wireless),
   tunnel = nil_table(tunnel),
   other = nil_table(other),
-  [json.null] = true
+  [{}] = true
 }
diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
index a67b9a07b19860e1ee47991b66a8bc06abdcfaa3..0d6d66f0ba4d9b0a6fd4f5570a7cb78071465317 100644
--- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
+++ b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn
@@ -1,4 +1,4 @@
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local ltn12 = require 'luci.ltn12'
 local nixio = require 'nixio'
 local site = require 'gluon.site_config'
@@ -11,8 +11,8 @@ if not fastd_sock:connect(socket_path) then
   return nil
 end
 
-local decoder = json.Decoder()
-ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink())
+local decoder = json.new()
+ltn12.pump.all(ltn12.source.file(fastd_sock), function(chunk) decoder:parse(chunk) end)
 
 local status = decoder:get()
 
@@ -27,7 +27,7 @@ local function peer_connection(config)
         established = peer.connection.established/1000
       }
     else
-      return json.null
+      return function()end -- nil
     end
   end
 end
diff --git a/package/gluon-status-page/Makefile b/package/gluon-status-page/Makefile
index 3d9edbfe1e932220b2512d472a14487f98623b9b..2543ea2ad15d19335e0a3d7cd3368efddb6eb78b 100644
--- a/package/gluon-status-page/Makefile
+++ b/package/gluon-status-page/Makefile
@@ -12,7 +12,7 @@ define Package/gluon-status-page
   SECTION:=gluon
   CATEGORY:=Gluon
   TITLE:=Adds a status page showing information about the node.
-  DEPENDS:=+gluon-core +uhttpd +gluon-neighbour-info +gluon-announce +libiwinfo-lua
+  DEPENDS:=+gluon-core +uhttpd +gluon-neighbour-info +gluon-announce +libiwinfo-lua +luci-lib-jsonc
 endef
 
 define Package/gluon-status-page/description
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
index addecd605a4647637ab138e4c64be4f09eb6f2fa..3bcdf89bd4c3b3b2d2406b38d5347f153d00d3bb 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/neighbours-batadv
@@ -1,6 +1,6 @@
 #!/usr/bin/lua
 
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local nixio = require 'nixio'
 
 function neighbours()
@@ -25,7 +25,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local neighbours = json.encode(neighbours())
+  local neighbours = json.stringify(neighbours())
   io.write("data: " .. neighbours .. "\n\n")
   io.flush()
   nixio.nanosleep(1, 0)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
index 4745c34222e5610dc2a1909cddd49329419c4d14..637de6499ff5b2b35ae493013809f30eebb52838 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 util = require 'luci.util'
-json = require 'luci.json'
+json = require 'luci.jsonc'
 nixio = require 'nixio'
 iwinfo = require 'iwinfo'
 
@@ -45,7 +45,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local stations = json.encode(get_stations(iw, ifname))
+  local stations = json.stringify(get_stations(iw, ifname))
   io.write("data: " .. stations .. "\n\n")
   io.flush()
   nixio.nanosleep(0, 150e6)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
index 7805afe836e561dc2ee32edf18eac7334682a635..194564b98740c4dae0ad3b48d5ba4b5be49b07df 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/dyn/statistics
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local util = require 'luci.util'
 local nixio = require 'nixio'
 
@@ -11,7 +11,7 @@ io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: text/event-stream\n\n")
 
 while true do
-  local data = json.encode(announce.collect_dir(announce_dir))
+  local data = json.stringify(announce.collect_dir(announce_dir))
   io.write("data: " .. data .. "\n\n")
   io.flush()
   nixio.nanosleep(1, 0)
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
index 2615ed823da8528394ef962cc2788bb5a33fc0c3..4eabf8158fa5899adac5dc885f2657565204e103 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/interfaces
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 util = require 'luci.util'
-json = require 'luci.json'
+json = require 'luci.jsonc'
 fs = require 'nixio.fs'
 
 io.write("Access-Control-Allow-Origin: *\n")
@@ -21,4 +21,4 @@ for _, line in ipairs(util.split(list)) do
   end
 end
 
-io.write(json.encode(interfaces))
+io.write(json.stringify(interfaces))
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
index a2ef61c7a258a01a57e28e52c330fb00b2dea36b..787892444bc0fed480e7f93da1634cfae3fee05c 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/nodeinfo
@@ -1,7 +1,7 @@
 #!/usr/bin/lua
 
 local announce = require 'gluon.announce'
-local json = require 'luci.json'
+local json = require 'luci.jsonc'
 local util = require 'luci.util'
 local nixio = require 'nixio'
 
@@ -10,6 +10,6 @@ local announce_dir = '/lib/gluon/announce/nodeinfo.d/'
 io.write("Access-Control-Allow-Origin: *\n")
 io.write("Content-type: application/json\n\n")
 
-local data = json.encode(announce.collect_dir(announce_dir))
+local data = json.stringify(announce.collect_dir(announce_dir))
 io.write(data)
 io.flush()
diff --git a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
index f0c8cbd851c04cc6febb1573c63b5346b0000871..fe4ba0af7b9b3ca897572ce42e21106d6984a557 100755
--- a/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
+++ b/package/gluon-status-page/files/lib/gluon/status-page/www/cgi-bin/status
@@ -4,7 +4,7 @@ local util = require("luci.util")
 local fs = require("nixio.fs")
 local ltn12 = require 'luci.ltn12'
 local sys = require("luci.sys")
-local json = require("luci.json")
+local json = require("luci.jsonc")
 local nixio = require 'nixio'
 local platform_info = require("platform_info")
 
@@ -20,7 +20,7 @@ function neighbours(ifname)
   local info = util.exec("gluon-neighbour-info -d ff02::2:1001 -p 1001 -r nodeinfo -t 3 -i " .. ifname)
   local macs = {}
   for _, line in ipairs(util.split(info)) do
-    local data = json.decode(line)
+    local data = json.parse(line)
     if data then
       local function add_macs(list)
         if list then
@@ -93,8 +93,8 @@ local stat, fastd_status = pcall(
     local fastd_sock = nixio.socket('unix', 'stream')
     assert(fastd_sock:connect('/var/run/fastd.mesh_vpn.socket'))
 
-    decoder = json.Decoder()
-    ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink())
+    decoder = json.new()
+    ltn12.pump.all(ltn12.source.file(fastd_sock), function(chunk) decoder:parse(chunk) end)
     return decoder:get()
   end
 )
diff --git a/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch b/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch
deleted file mode 100644
index ab02429c8217f76acb38fef7ae3d8c0b49eccda7..0000000000000000000000000000000000000000
--- a/patches/packages/luci/0004-luci-lib-json-ignore-null-keys-to-allow-encoding-empty-objects.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Thu, 4 Jun 2015 21:03:24 +0200
-Subject: luci-lib-json: ignore null keys to allow encoding empty objects
-
-There is currently no way to encode an empty object {}, as empty tables are
-encoded as empty lists [].
-
-With this patch, encode() will ignore table fields with the key json.null (which
-doesn't make sense anyways). This allows adding a field with key json.null to
-force encoding it as an object.
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-
-diff --git a/libs/luci-lib-json/luasrc/json.lua b/libs/luci-lib-json/luasrc/json.lua
-index 416b25f..f7b57f9 100644
---- a/libs/luci-lib-json/luasrc/json.lua
-+++ b/libs/luci-lib-json/luasrc/json.lua
-@@ -149,11 +149,13 @@ function Encoder.parse_iter(self, obj)
- 		local first = true
- 
- 		for key, entry in pairs(obj) do
--			first = first or self:put(",")
--			first = first and false
--			self:parse_string(tostring(key))
--			self:put(":")
--			self:dispatch(entry)
-+			if key ~= null then
-+				first = first or self:put(",")
-+				first = first and false
-+				self:parse_string(tostring(key))
-+				self:put(":")
-+				self:dispatch(entry)
-+			end
- 		end
- 
- 		self:put("}")
diff --git a/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch b/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch
new file mode 100644
index 0000000000000000000000000000000000000000..584a2fab82c9fe6d4b94265fe381ff05385a9c60
--- /dev/null
+++ b/patches/packages/luci/0004-luci-lib-jsonc-Ignore-non-string-or-number-keys-in-tables.patch
@@ -0,0 +1,32 @@
+From: Jan-Philipp Litza <janphilipp@litza.de>
+Date: Sun, 30 Aug 2015 15:42:52 +0200
+Subject: luci-lib-jsonc: Ignore non-string-or-number keys in tables
+
+Previously, the following caused a segmentation fault:
+
+    json.stringify({[{}] = true})
+
+This was caused by lua_tostring() returning NULL for anything but
+strings and numbers, letting json_object_object_add crash.
+
+This patch makes jsonc ignore all keys which have no string
+representation altogether.
+
+Signed-off-by: Jan-Philipp Litza <janphilipp@litza.de>
+
+diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
+index 49cb21f..827fde8 100644
+--- a/libs/luci-lib-jsonc/src/jsonc.c
++++ b/libs/luci-lib-jsonc/src/jsonc.c
+@@ -286,8 +286,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
+ 			lua_pushvalue(L, -2);
+ 			key = lua_tostring(L, -1);
+ 
+-			json_object_object_add(obj, key,
+-								   _lua_to_json(L, lua_gettop(L) - 1));
++			if (key)
++				json_object_object_add(obj, key,
++				                       _lua_to_json(L, lua_gettop(L) - 1));
+ 
+ 			lua_pop(L, 2);
+ 		}
diff --git a/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch b/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8d6b6842e987888af14d2fcbf677fd408436f4dc
--- /dev/null
+++ b/patches/packages/luci/0005-luci-lib-jsonc-allow-encoding-empty-lists.patch
@@ -0,0 +1,38 @@
+From: Jan-Philipp Litza <janphilipp@litza.de>
+Date: Sun, 30 Aug 2015 15:45:49 +0200
+Subject: luci-lib-jsonc: allow encoding empty lists
+
+To be consistent with the behavior of luci-lib-json, an empty Lua table
+should be encoded to an empty JSON list, not an empty JSON object.
+
+To still allow encoding empty JSON objects, the usage of anything other
+than a number or a string as a key (for example an empty table or a
+function) can be used to force encoding as an object:
+
+    json.stringify({})                  -- "[]"
+    json.stringify({[{}] = true})       -- "{}"
+
+Signed-off-by: Jan-Philipp Litza <janphilipp@litza.de>
+
+diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
+index 827fde8..971fb12 100644
+--- a/libs/luci-lib-jsonc/src/jsonc.c
++++ b/libs/luci-lib-jsonc/src/jsonc.c
+@@ -222,7 +222,7 @@ static int _lua_test_array(lua_State *L, int index)
+ 
+ out:
+ 		lua_pop(L, 2);
+-		return 0;
++		return -1;
+ 	}
+ 
+ 	/* check for holes */
+@@ -254,7 +254,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
+ 	case LUA_TTABLE:
+ 		max = _lua_test_array(L, index);
+ 
+-		if (max > 0)
++		if (max >= 0)
+ 		{
+ 			obj = json_object_new_array();
+