{"id":2564,"date":"2022-04-28T15:22:42","date_gmt":"2022-04-28T19:22:42","guid":{"rendered":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/?p=2564"},"modified":"2022-04-30T10:33:18","modified_gmt":"2022-04-30T14:33:18","slug":"final-crit-james-kyle","status":"publish","type":"post","link":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/?p=2564","title":{"rendered":"Final Crit &#8211; James Kyle"},"content":{"rendered":"<h1 style=\"text-align: center\"><span style=\"text-decoration: underline\"><strong>Sims&#8230;but its you<\/strong><\/span><\/h1>\n<p><img loading=\"lazy\" class=\" wp-image-2572 aligncenter\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-300x156.png\" alt=\"\" width=\"604\" height=\"314\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-300x156.png 300w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-1024x533.png 1024w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-768x400.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-1536x799.png 1536w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-2048x1066.png 2048w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.06.43-PM-1200x624.png 1200w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<p>&nbsp;<\/p>\n<h5 style=\"text-align: center\"><span style=\"text-decoration: underline\"><strong>Description:<\/strong><\/span><\/h5>\n<p>I decided to take my previous visual crit further for this final crit by adding more components from a typical house into the control scheme\/visualization method. The idea is to create a little virtual world where the user can visualize and interact with things going on in their home related to electronics. The user has the ability to turn lamps on and off and the states of each lamp will brighten the virtual room accordingly.<\/p>\n<figure id=\"attachment_2568\" aria-describedby=\"caption-attachment-2568\" style=\"width: 300px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" class=\"wp-image-2568 size-medium\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.17-PM-300x164.png\" alt=\"\" width=\"300\" height=\"164\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.17-PM-300x164.png 300w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.17-PM-1024x561.png 1024w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.17-PM-768x421.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.17-PM.png 1128w\" sizes=\"(max-width: 300px) 85vw, 300px\" \/><figcaption id=\"caption-attachment-2568\" class=\"wp-caption-text\">Lamps both off<\/figcaption><\/figure>\n<figure id=\"attachment_2569\" aria-describedby=\"caption-attachment-2569\" style=\"width: 362px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" class=\"wp-image-2569 \" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.23-PM-300x164.png\" alt=\"\" width=\"362\" height=\"198\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.23-PM-300x164.png 300w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.23-PM-1024x561.png 1024w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.23-PM-768x421.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.02.23-PM.png 1128w\" sizes=\"(max-width: 362px) 85vw, 362px\" \/><figcaption id=\"caption-attachment-2569\" class=\"wp-caption-text\">One lamp on and one lamp off<\/figcaption><\/figure>\n<p>The user can also see whether someone is at the door and let them inside if they so choose. I did not know how to connect a camera to the Arduino so the system is not able to distinguish who is at the door but that is a future addition to theoretical implementation of this concept. Assuming the user knows the person present at the door, they can click the lock next to the door and unlock the door for the user.<\/p>\n<figure id=\"attachment_2573\" aria-describedby=\"caption-attachment-2573\" style=\"width: 576px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"wp-image-2573\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-300x78.png\" alt=\"\" width=\"576\" height=\"150\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-300x78.png 300w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-1024x267.png 1024w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-768x200.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-1536x400.png 1536w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM-1200x313.png 1200w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.12.35-PM.png 2002w\" sizes=\"(max-width: 576px) 85vw, 576px\" \/><figcaption id=\"caption-attachment-2573\" class=\"wp-caption-text\">Process for unlocking door<\/figcaption><\/figure>\n<p>The user also has visual indications of the temperature and thermostat setting through a heater\/ac unit. The color of the unit dynamically changes based on the difference between the goal temperature and current temperature in the room. If the room is hotter than it should be, the unit appears more blue to indicate that the ac is running. The same is true for the opposite scenario as well where the room is colder than desired.<\/p>\n<figure id=\"attachment_2574\" aria-describedby=\"caption-attachment-2574\" style=\"width: 627px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" class=\"wp-image-2574\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-300x112.png\" alt=\"\" width=\"627\" height=\"234\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-300x112.png 300w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-1024x384.png 1024w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-768x288.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-1536x576.png 1536w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-2048x768.png 2048w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/Screen-Shot-2022-04-28-at-3.14.58-PM-1200x450.png 1200w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><figcaption id=\"caption-attachment-2574\" class=\"wp-caption-text\">Temperature settings and their color representation<\/figcaption><\/figure>\n<h5 style=\"text-align: center\"><span style=\"text-decoration: underline\">Circuit:<\/span><\/h5>\n<p><img loading=\"lazy\" class=\"wp-image-2591 aligncenter\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-225x300.jpg\" alt=\"\" width=\"468\" height=\"624\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-225x300.jpg 225w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-768x1024.jpg 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-1152x1536.jpg 1152w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-1536x2048.jpg 1536w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-1200x1600.jpg 1200w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7866-scaled.jpg 1920w\" sizes=\"(max-width: 468px) 85vw, 468px\" \/><\/p>\n<h5 style=\"text-align: center\"><img loading=\"lazy\" class=\"alignnone  wp-image-2590\" src=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-225x300.png\" alt=\"\" width=\"433\" height=\"578\" srcset=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-225x300.png 225w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-768x1024.png 768w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-1152x1536.png 1152w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-1536x2048.png 1536w, https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/wp-content\/uploads\/2022\/04\/IMG_7867-1200x1600.png 1200w\" sizes=\"(max-width: 433px) 85vw, 433px\" \/><\/h5>\n<h5 style=\"text-align: center\"><span style=\"text-decoration: underline\"><strong>Demo Video:<\/strong><\/span><\/h5>\n<p><iframe loading=\"lazy\" title=\"Final Crit Demo 1\" width=\"840\" height=\"473\" src=\"https:\/\/www.youtube.com\/embed\/xcY5RwwcGqA?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<p><iframe loading=\"lazy\" title=\"Final Crit Demo 2\" width=\"840\" height=\"473\" src=\"https:\/\/www.youtube.com\/embed\/MgloN5KvQQc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe><\/p>\n<p>&nbsp;<\/p>\n<h5 style=\"text-align: center\"><span style=\"text-decoration: underline\"><strong>Code:<\/strong><\/span><\/h5>\n<h6>p5.js<\/h6>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">\/*\r\n\r\n\r\n- RGB to HSV Conversion Function from http:\/\/www.javascripter.net\/faq\/rgb2hsv.htm\r\n\r\n\r\n*\/\r\nlet serial;\r\nlet latestData = \"waiting for data\";\r\nvar outMessage;\r\nvar prevOutMessage;\r\nvar message;\r\nvar currentMessage;\r\n\r\nlet goalTemp = 0;\r\nlet currTemp = 0;\r\n\r\nlet newFont;\r\nlet lightsEnable = true;\r\n\r\nlet x = 100;\r\nlet y = 100;\r\n\r\nlet width = 1700;\r\nlet height = 900;\r\n\r\nlet color = 300;\r\nlet baseSaturation = 40;\r\nlet baseBrightness = 30;\r\n\r\nlet table1X = 970;\r\nlet table2X = 630;\r\nlet table1Y = 200;\r\n\r\n\/\/Lightsource vector [on\/off, x, y, Lamp Radius, Shine Radius]\r\nlet lightSources = [];\r\n\r\nlet updateLightSource = true;\r\n\r\n\/\/States\r\nlet heaterState = 0;\r\nlet acState = 1;\r\n\r\n\/\/Colors\r\nlet doorStepColor = [50, 50, 50];\r\nlet lockColor = [255, 0, 0];\r\nlet heaterColor = [255, 150, 173];\r\n\r\n\r\n\/\/Positions\r\nlet heaterX = 375;\r\nlet heaterY = 250;\r\n\r\nlet livingRoomWidth = width - 600;\r\nlet livingRoomHeight = height - 100;\r\n\r\nlet doorStepHeight = 200;\r\nlet doorStepWidth = 200;\r\n\r\nlet lockX = width\/2 + livingRoomWidth\/2 + 10;\r\nlet lockY = height\/2 + livingRoomHeight\/2 - doorStepHeight\/2 - 60;\r\nlet lockState = 0;\r\n\r\n\r\nlet minDistIndex = 0;\r\n\r\n\r\nfunction setup() {\r\n  createCanvas(width, height);\r\n\r\n  \/\/Lamps initiation\r\n  lightSources[0] = [0, table1X, table1Y, 40, 200];\r\n  lightSources[1] = [0, table2X, table1Y, 40, 200];\r\n  \r\n  \r\n  serial = new p5.SerialPort();\r\n\r\n  serial.list();\r\n  serial.open('\/dev\/tty.usbmodem114697101');\r\n\r\n  serial.on('connected', serverConnected);\r\n\r\n  serial.on('list', gotList);\r\n\r\n  serial.on('data', gotData);\r\n\r\n  serial.on('error', gotError);\r\n\r\n  serial.on('open', gotOpen);\r\n\r\n  serial.on('close', gotClose);\r\n}\r\n\r\nfunction serverConnected() {\r\n  print(\"Connected to Server\");\r\n }\r\n \r\n function gotList(thelist) {\r\n  print(\"List of Serial Ports:\");\r\n \r\n  for (let i = 0; i &lt; thelist.length; i++) {\r\n   print(i + \" \" + thelist[i]);\r\n  }\r\n }\r\n \r\n function gotOpen() {\r\n  print(\"Serial Port is Open\");\r\n }\r\n \r\n function gotClose(){\r\n  print(\"Serial Port is Closed\");\r\n  latestData = \"Serial Port is Closed\";\r\n }\r\n \r\n function gotError(theerror) {\r\n  print(theerror);\r\n }\r\n \r\n function gotData() {\r\n   let currentString = serial.readLine();\r\n   trim(currentString);\r\n   if (!currentString) return;\r\n   console.log(currentString);\r\n   latestData = currentString;\r\n\r\n   if (latestData != currentMessage) {\r\n    currentMessage = latestData;\r\n    handleInputData(latestData);\r\n   }\r\n }\r\n\r\n function handleInputData(latestData) {\r\n\r\n\/\/Current temperature\r\n  if (latestData\/10 &gt;= 70) {\r\n    currTemp = latestData - 700;\r\n  }\r\n\r\n\r\n\/\/Goal temperature\r\n  else if (latestData\/10 &gt;= 60) {\r\n    goalTemp = latestData - 600;\r\n  }\r\n\r\n  \/\/Presence at door\r\n  else if (latestData\/10 &gt;= 4) {\r\n    if (latestData == 41) {\r\n      doorStepColor = [255, 255, 255];\r\n    } else if (latestData == 40) {\r\n      doorStepColor = [50, 50, 50];\r\n    }\r\n  }\r\n\r\n  \/\/Lock\r\n  else if (latestData\/10 &gt;= 3) {\r\n    if (latestData == 30){\r\n      lockState = 0;\r\n      toggleLockColor(lockState);\r\n    } else if (latestData == 31) {\r\n      lockState = 1;\r\n      toggleLockColor(lockState);\r\n    }\r\n   }\r\n\r\n   \/\/Lamp 2\r\n  else if (latestData\/10 &gt;= 2) {\r\n    if (latestData == 20){\r\n      lightSources[1][0] = 0;\r\n    } else if (latestData == 21) {\r\n      lightSources[1][0] = 1;\r\n    }\r\n   }\r\n\r\n  \/\/Lamp 1\r\n  else if (latestData\/10 &gt;= 1) {\r\n    if (latestData == 10){\r\n      lightSources[0][0] = 0;\r\n    } else if (latestData == 11) {\r\n      lightSources[0][0] = 1;\r\n    }\r\n   }\r\n}\r\n\r\n\r\n \r\nfunction draw() {\r\n\r\n  colorMode(HSB);\r\n  background(128, 20, 70);\r\n\r\n\r\n  \/\/House top view\r\n  \/\/================================\r\n  push();\r\n  colorMode(RGB);\r\n  rectMode(CENTER);\r\n  stroke(0);\r\n  strokeWeight(10);\r\n  fill(50);\r\n  rect(width\/2, height\/2,livingRoomWidth,livingRoomHeight);\r\n\r\n  \/\/Room\r\n  fill(50);\r\n  stroke(0);\r\n  strokeWeight(0);\r\n  rect(width\/2 + livingRoomWidth\/2, height\/2 + livingRoomHeight\/2 - doorStepHeight\/2,100,75);\r\n\r\n  \/\/Door step\r\n  fill(doorStepColor[0],doorStepColor[1],doorStepColor[2]);\r\n  stroke(0);\r\n  strokeWeight(0);\r\n  rect(width\/2 + livingRoomWidth\/2 + doorStepWidth\/2 + 5, height\/2 + livingRoomHeight\/2 - doorStepHeight\/2,doorStepWidth,doorStepHeight);\r\n  \r\n  \/\/Lock\r\n  fill(lockColor[0], lockColor[1],lockColor[2]);\r\n  rect(lockX, lockY,10,30);\r\n  pop();\r\n  \/\/============================\r\n\r\n  \/\/Heater\r\n  drawHeater(heaterX, heaterY, 200, 80, PI\/2);\r\n\r\n  \/\/Couch\r\n  drawCouch(800, 200, 80, 200, 0, 50, 40, 80);\r\n\r\n  \/\/Chairs\r\n  drawCouch(980, 300, 80, 80, PI\/2, 50, 40, 80);\r\n  drawCouch(620, 300, 80, 80, -PI\/2, 50, 40, 80);\r\n\r\n  \/\/Coffee table\r\n  drawTable(800, 300, 80, 200, PI, 30, 40, 30);\r\n\r\n  \/\/Lamp tables\r\n  drawTable(table1X, table1Y, 80, 80, 0, 30, 40, 30);\r\n  drawTable(table2X, table1Y, 80, 80, 0, 30, 40, 30);\r\n\r\n  for (k = 0; k &lt; lightSources.length; k++) {\r\n    fill(200, 40, 60);\r\n    drawLamp(lightSources[k][1], lightSources[k][2], lightSources[k][3]);\r\n  }\r\n\r\n\r\n\r\n  for (n = 0; n &lt; lightSources.length; n++) {\r\n    if (lightSources[n][0] == 1) {\r\n      turnLightOn(lightSources[n][1], lightSources[n][2], lightSources[n][3], lightSources[n][4]);\r\n    }\r\n  }\r\n\r\n  push();\r\n  fill(0);\r\n  textAlign(CENTER);\r\n  textSize(20);\r\n  text(\"House Setting: \" + goalTemp, 50, 100, 150, 100);\r\n  text(\"Room Temperature: \" + currTemp, 30, 180, 190, 100);\r\n  pop();\r\n\r\n \r\n}\r\n\r\n\r\nfunction updateLightState(lightIndex) {\r\n  lightIndex = Number(lightIndex);\r\n  if (lightSources[lightIndex][0] == 1) {\r\n      lightSources[lightIndex][0] = 0;\r\n      if (lightIndex == 0) { \r\n        currentMessage = 10;\r\n        sendMessage(currentMessage);\r\n      } else if (lightIndex == 1){\r\n        currentMessage = 20;\r\n        sendMessage(currentMessage);\r\n      }\r\n  }\r\n\r\n  else if (lightSources[lightIndex][0] == 0) {\r\n      lightSources[lightIndex][0] = 1;\r\n      if (lightIndex == 0) { \r\n        currentMessage = 11;\r\n        sendMessage(currentMessage);\r\n      } else if (lightIndex == 1){\r\n        currentMessage = 21;\r\n        sendMessage(currentMessage);\r\n      }\r\n  }\r\n}\r\n\r\n\r\nfunction mousePressed() {\r\n\r\n  let currX = mouseX;\r\n  let currY = mouseY;\r\n\r\n  dist2Lamp1 = sqrt(pow((currX-lightSources[0][1]),2) + pow((currY-lightSources[0][2]),2));\r\n  dist2Lamp2 = sqrt(pow((currX-lightSources[1][1]),2) + pow((currY-lightSources[1][2]),2));\r\n  dist2Heater = sqrt(pow((currX-heaterX),2) + pow((currY-heaterY),2));\r\n  dist2Lock = sqrt(pow((currX-lockX),2) + pow((currY-lockY),2));\r\n\r\n  let minDistIndex = 0;\r\n  let distVector = [dist2Lamp1,dist2Lamp2,dist2Heater,dist2Lock];\r\n\r\n  for (i = 1; i &lt; 4; i++) { \r\n    if (distVector[minDistIndex] &gt; distVector[i]) {\r\n      minDistIndex = i;\r\n    }\r\n  }\r\n\r\n  if (minDistIndex == 0) {\r\n    if (dist2Lamp1 &lt; lightSources[0][3]*2) {\r\n      updateLightState(0);\r\n    }\r\n\r\n  }\r\n\r\n  if (minDistIndex == 1) {\r\n    if (dist2Lamp2 &lt; lightSources[1][3]*2) {\r\n      updateLightState(1);\r\n    }\r\n  }\r\n\r\n  if (minDistIndex == 3) {\r\n    \r\n    if (currX &lt; lockX + 5 &amp;&amp; currX &gt; lockX - 5) {\r\n      if (currY &lt; lockY + 15 &amp;&amp; currY &gt; lockY - 15) {\r\n        lockState = !lockState;\r\n        toggleLockColor();\r\n      }\r\n    }\r\n  }\r\n\r\n}\r\n\r\n\r\nfunction turnLightOn(x, y, lampRadius, shineRadius) {\r\n  var centerX = x;\r\n  var centerY = y;\r\n\r\n\r\n  \/\/Iterating through each point in square to brighten color if inside lamp shine radius\r\n  for (i = 0; i &lt; 2*shineRadius; i = i+5) {\r\n    for (j = 0; j &lt; 2*shineRadius; j = j+5) {\r\n      var currX = centerX - shineRadius + i;\r\n      var currY = centerY - shineRadius + j;\r\n\r\n      var dist2Center = sqrt(pow((centerX - currX),2) + pow((centerY - currY),2));\r\n\r\n      if (dist2Center &lt;= shineRadius) {\r\n        var currColor = get(currX, currY);\r\n        hsvConversion = rgb2hsv(currColor[0], currColor[1], currColor[2]);\r\n\r\n        colorMode(HSB);\r\n        stroke(hsvConversion[0], hsvConversion[1]+40, hsvConversion[2]+20);\r\n        strokeWeight(7);\r\n        point(currX, currY);\r\n      }\r\n\r\n    }\r\n  }\r\n \r\n  strokeWeight(0);\r\n}\r\n\r\n\r\n\r\nfunction drawCouch(x, y, width, height, theta, couchH, couchS, couchB) {\r\n\r\n  let couchHeight = width;\r\n  let couchWidth = height;\r\n  let armWidth = couchWidth*1\/5;\r\n  let armHeight = couchHeight*4\/5;\r\n  let backWidth = couchWidth;\r\n  let backHeight = couchHeight*2\/5;\r\n\r\n  \/\/Base Couch\r\n  push();\r\n  angleMode(RADIANS);\r\n  rectMode(CENTER);\r\n  translate(x, y);\r\n  rotate(theta);\r\n  \/\/ translate(transRadius - transRadius*cos(theta), -transRadius*sin(theta));\r\n\r\n  strokeWeight(2);\r\n  stroke(0);\r\n  fill(couchH, couchS, couchB);\r\n  rect(0, 0, couchWidth, couchHeight, 0, 0, 10, 10);\r\n\r\n  \/\/Arm rests\r\n  fill(couchH, couchS, couchB - 20);\r\n  rect(-couchWidth\/2, armHeight - couchHeight, armWidth, armHeight, 10, 10, 10, 10);\r\n  rect(couchWidth\/2, armHeight - couchHeight, armWidth, armHeight, 10, 10, 10, 10);\r\n\r\n  \/\/Backing\r\n  fill(couchH, couchS, couchB - 25);\r\n  rect(0, (armHeight\/2 - couchHeight\/2) + (backHeight\/2 - couchHeight\/2), backWidth, backHeight, 0, 0, 30, 30);\r\n  strokeWeight(0);\r\n\r\n\r\n  pop();\r\n\r\n}\r\n\r\nfunction drawTable(x, y, width, height, theta, couchH, couchS, couchB) {\r\n\r\n  let tableHeight = width;\r\n  let tableWidth = height;\r\n\r\n  \/\/Base Couch\r\n  push();\r\n  angleMode(RADIANS);\r\n  rectMode(CENTER);\r\n  translate(x, y);\r\n  rotate(theta);\r\n  \/\/ translate(transRadius - transRadius*cos(theta), -transRadius*sin(theta));\r\n\r\n  \/\/Table top\r\n  strokeWeight(2);\r\n  stroke(0);\r\n  fill(couchH, couchS, couchB);\r\n  rect(0, 0, tableWidth, tableHeight);\r\n\r\n  \/\/Top pattern\r\n  strokeWeight(2);\r\n  stroke(0);\r\n  fill(couchH, couchS, couchB + 40);\r\n  rect(0, 0, tableWidth - 10, tableHeight - 10);\r\n\r\n  pop();\r\n\r\n}\r\n\r\n\r\nfunction drawLamp(x, y, radius, couchH, couchS, couchB) {\r\n\r\n  let tableHeight = width;\r\n  let tableWidth = height;\r\n\r\n  \/\/Base Couch\r\n  push();\r\n\r\n  \/\/Lamp\r\n  fill(couchH, couchS, couchB);\r\n  ellipse(x, y, radius);\r\n\r\n  pop();\r\n\r\n}\r\n\r\nfunction drawHeater(x, y, width, height, theta) {\r\n\r\n  let heaterWidth = width;\r\n  let heaterHeight = height;\r\n  let numOfFins = 20;\r\n  let finWidth = heaterWidth\/numOfFins - 4 - 8\/numOfFins;\r\n  let finHeight = height\/2 - 10;\r\n\r\n  let tempDiff = goalTemp - currTemp;\r\n\r\n  heaterColor = [220+2*tempDiff, 180, 200-tempDiff];\r\n\r\n  \/\/Base Couch\r\n  push();\r\n  colorMode(RGB);\r\n  angleMode(RADIANS);\r\n  rectMode(CENTER);\r\n  translate(x, y);\r\n  rotate(theta);\r\n  \/\/ translate(transRadius - transRadius*cos(theta), -transRadius*sin(theta));\r\n\r\n  \/\/Heater Base\r\n  strokeWeight(0);\r\n  fill(heaterColor[0], heaterColor[1], heaterColor[2]);\r\n  rect(0, 0, heaterWidth, heaterHeight, 5, 5, 5, 5);\r\n\r\n  \/\/Top pattern\r\n  strokeWeight(2);\r\n  stroke(0);\r\n  fill(117, 109, 94);\r\n  for (i = 0; i &lt; numOfFins; i++) {\r\n    let currX = 0 - heaterWidth\/2 + (finWidth+12)\/2 + (finWidth+4)*(i);\r\n    rect(currX, finHeight\/2+5, finWidth, finHeight, finHeight\/2, finHeight\/2, finHeight\/2);\r\n    rect(currX, -finHeight\/2-5, finWidth, finHeight, finHeight\/2, finHeight\/2, finHeight\/2);\r\n  }\r\n  \r\n  pop();\r\n\r\n}\r\n\r\n\r\nfunction toggleLockColor() {\r\n  if (lockState) {\r\n    lockColor = [0, 255, 0];\r\n    currentMessage = 31;\r\n    sendMessage(currentMessage);\r\n  } else {\r\n    lockColor = [255, 0, 0];\r\n    currentMessage = 30;\r\n    sendMessage(currentMessage);\r\n  }\r\n}\r\n\r\n\r\nfunction rgb2hsv (r,g,b) {\r\n var computedH = 0;\r\n var computedS = 0;\r\n var computedV = 0;\r\n\r\n \/\/remove spaces from input RGB values, convert to int\r\n var r = parseInt( (''+r).replace(\/\\s\/g,''),10 );\r\n var g = parseInt( (''+g).replace(\/\\s\/g,''),10 );\r\n var b = parseInt( (''+b).replace(\/\\s\/g,''),10 );\r\n\r\n if ( r==null || g==null || b==null ||\r\n     isNaN(r) || isNaN(g)|| isNaN(b) ) {\r\n   alert ('Please enter numeric RGB values!');\r\n   return;\r\n }\r\n if (r&lt;0 || g&lt;0 || b&lt;0 || r&gt;255 || g&gt;255 || b&gt;255) {\r\n   alert ('RGB values must be in the range 0 to 255.');\r\n   return;\r\n }\r\n r=r\/255; g=g\/255; b=b\/255;\r\n var minRGB = Math.min(r,Math.min(g,b));\r\n var maxRGB = Math.max(r,Math.max(g,b));\r\n\r\n \/\/ Black-gray-white\r\n if (minRGB==maxRGB) {\r\n  computedV = minRGB;\r\n  return [0,0,computedV];\r\n }\r\n\r\n \/\/ Colors other than black-gray-white:\r\n var d = (r==minRGB) ? g-b : ((b==minRGB) ? r-g : b-r);\r\n var h = (r==minRGB) ? 3 : ((b==minRGB) ? 1 : 5);\r\n computedH = 60*(h - d\/(maxRGB - minRGB));\r\n computedS = (maxRGB - minRGB)\/maxRGB;\r\n computedV = maxRGB;\r\n return [computedH,computedS*100,computedV*100];\r\n}\r\n\r\nfunction sendMessage(message) {\r\n  for (i = 0; i &lt; 1; i++) {\r\n    \/\/Output message to serial\r\n    serial.write(int(message));\r\n  }\r\n}\r\n<\/pre>\n<h6>Arduino<\/h6>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">\/*\r\n\r\n   References:\r\n      - Temperature Reading Code: https:\/\/www.circuitbasics.com\/arduino-thermistor-temperature-sensor-tutorial\/\r\n\r\n\r\n\r\n\r\n   Goal: bring control of home to digital interface on p5.js\r\n\r\n   1. Lights\r\n      - ON\/OFF through p5.js (100%)\r\n      - State control based on presence in room (0%)\r\n\r\n   2. Temperature\r\n      - Holding temperature (70%)\r\n      - Indication of heater and ac states through p5.js (0%)\r\n\r\n   3. Doorbell\r\n      - Represent door presence through p5.js (30%)\r\n      - Unlock door through p5.js (80%) --&gt; motor (CHECK), lights (CHECK), and sound to indicate to user that door is unlocked\r\n\r\n   4. TV\r\n      - Control ON\/OF based on presence on couch (0%)\r\n\r\n   5. Notifications\r\n      - Notify user of house happenings through p5.js (0%)\r\n      - Take input through p5.js (0%)\r\n\r\n\r\n\r\n   Communication Protocol:\r\n   1 - lamp 1\r\n   2 - lamp 2\r\n   3 - lock state --&gt; 1=unlocked; 0=locked\r\n   4 - presence state\r\n   5 - heater on? --&gt; 1=yes; 0=no\r\n   6 - current temp\r\n\r\n\r\n\r\n*\/\r\n\r\n#include &lt;Servo.h&gt;\r\n\r\n\r\n#define lamp1pin 17\r\n#define lamp2pin 16\r\n#define button1 14\r\n#define button2 40\r\n\r\n#define coldPin             10\r\n#define hotPin              11\r\n#define tempSensor1         20\r\n#define sliderPin           21\r\n\r\n#define pressurePlate       19\r\n#define presenceIndicator   8\r\n#define lockButton          28\r\n#define lockLight           38\r\n#define unlockLight         35\r\n\r\n\r\n\/\/================\/\/\r\n\/\/==Temp Control==\/\/\r\n\/\/================\/\/\r\nbool heaterON = true;\r\nbool acON = true;\r\n\r\nlong double prevTempTime = 0;\r\nint tempTimerDuration = 2; \/\/ [s]\r\n\r\n\r\n\/\/========\/\/\r\n\/\/==Lock==\/\/\r\n\/\/========\/\/\r\nunsigned long debounceTimerLock = 0;\r\nint debounceTimeLock = 300;\r\nbool DEBOUNCE_LOCK = false;\r\nbool firstCountLock = true;\r\nvolatile int lockState = 0; \/\/ 0 =&gt; locked; 1 =&gt; unlocked\r\n\r\nint unlockTimer = 3000;\r\nlong double prevUnlockTime = 0;\r\n\r\nServo lockServo;\r\n\r\n\r\n\/\/=========\/\/\r\n\/\/==Lamps==\/\/\r\n\/\/=========\/\/\r\nunsigned long debounceTimer1 = 0;\r\nint debounceTime1 = 300;\r\nbool DEBOUNCE1 = false;\r\nbool firstCount1 = true;\r\n\r\nunsigned long debounceTimer2 = 0;\r\nint debounceTime2 = 300;\r\nbool DEBOUNCE2 = false;\r\nbool firstCount2 = true;\r\n\r\n\r\nvolatile int lamp1state = 0;\r\nvolatile int lamp2state = 0;\r\n\r\n\r\n\/\/=================\/\/\r\n\/\/==Communication==\/\/\r\n\/\/=================\/\/\r\nint currentMessage;\r\nint prevMessage;\r\nint prevInMessage;\r\nint inMessage;\r\nbool receivedMessage = false;\r\n\r\n\r\nvoid setup() {\r\n  \/\/ put your setup code here, to run once:\r\n\r\n  pinMode(lamp1pin, OUTPUT);\r\n  pinMode(lamp2pin, OUTPUT);\r\n  pinMode(coldPin, OUTPUT);\r\n  pinMode(hotPin, OUTPUT);\r\n  pinMode(button1, INPUT_PULLUP);\r\n  pinMode(button2, INPUT_PULLUP);\r\n  attachInterrupt(digitalPinToInterrupt(button1), button1Pressed, CHANGE);\r\n  attachInterrupt(digitalPinToInterrupt(button2), button2Pressed, CHANGE);\r\n\r\n  pinMode(tempSensor1, INPUT);\r\n  pinMode(sliderPin, INPUT);\r\n\r\n  pinMode(pressurePlate, INPUT);\r\n  pinMode(lockButton, INPUT_PULLUP);\r\n\r\n  attachInterrupt(digitalPinToInterrupt(lockButton), handleLockButton, CHANGE);\r\n  Serial.begin(9600);\r\n\r\n  lockServo.attach(29);\r\n  lockServo.write(0);\r\n  delay(15);\r\n}\r\n\r\nvoid loop() {\r\n\r\n  \/\/if main computer sent a command\r\n  if ( Serial.available() &gt; 0) {\r\n    int c = Serial.read();\r\n    parseInput(c);\r\n  }\r\n\r\n  doPlatePresenceCheck();\r\n\r\n\r\n  \/\/Handling heater check\r\n  if (millis() \/ 1000.0 - prevTempTime &gt; tempTimerDuration) {\r\n    prevTempTime = millis() \/ 1000.0;\r\n    checkTemp();\r\n  }\r\n\r\n\r\n\r\n  \/\/Debounce for lock\r\n  if (DEBOUNCE_LOCK &amp;&amp; firstCountLock) {\r\n    debounceTimerLock = millis();\r\n    firstCountLock = false;\r\n    toggleLockState(lockState);\r\n  }\r\n\r\n  if (millis() - debounceTimerLock &gt; debounceTimeLock) {\r\n    DEBOUNCE_LOCK = false;\r\n    firstCountLock = true;\r\n  }\r\n\r\n  if (millis() - prevUnlockTime &gt; unlockTimer &amp;&amp; lockState) {\r\n    lockState = 0;\r\n    toggleLockState(lockState);\r\n  }\r\n\r\n\r\n\r\n  \/\/Debounce for lamp 1\r\n  if (DEBOUNCE1 &amp;&amp; firstCount1) {\r\n    debounceTimer1 = millis();\r\n    firstCount1 = false;\r\n    currentMessage = 10 + lamp1state;\r\n    sendMessage(currentMessage);\r\n  }\r\n\r\n  if (millis() - debounceTimer1 &gt; debounceTime1) {\r\n    DEBOUNCE1 = false;\r\n    firstCount1 = true;\r\n  }\r\n\r\n\r\n\r\n  \/\/Debounce for lamp 2\r\n  if (DEBOUNCE2 &amp;&amp; firstCount2) {\r\n    debounceTimer2 = millis();\r\n    firstCount2 = false;\r\n    currentMessage = 20 + lamp2state;\r\n    sendMessage(currentMessage);\r\n  }\r\n  if (millis() - debounceTimer2 &gt; debounceTime2) {\r\n    DEBOUNCE2 = false;\r\n    firstCount2 = true;\r\n  }\r\n\r\n}\r\n\r\nvoid checkTemp() {\r\n\r\n  int Vo;\r\n  float R1 = 10000;\r\n  float logR2, R2, T;\r\n  float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;\r\n\r\n  float minTemp = 60;\r\n  float maxTemp = 90;\r\n  float goalTemp;\r\n\r\n  Vo = analogRead(tempSensor1);\r\n  R2 = R1 * (1023.0 \/ (float)Vo - 1.0);\r\n  logR2 = log(R2);\r\n  T = (1.0 \/ (c1 + c2 * logR2 + c3 * logR2 * logR2 * logR2));\r\n  T = T - 273.15;\r\n  T = (T * 9.0) \/ 5.0 + 32.0;\r\n\r\n  goalTemp  = map(analogRead(sliderPin), 0, 1023, minTemp, maxTemp);\r\n  currentMessage = 600 + goalTemp;\r\n  sendMessage(currentMessage);\r\n\r\n  currentMessage = 700 + T;\r\n  sendMessage(currentMessage);\r\n\r\n\r\n  if (goalTemp &gt; T &amp;&amp; acON) {\r\n    digitalWrite(hotPin, HIGH);\r\n    digitalWrite(coldPin, LOW);\r\n    heaterON = true;\r\n    acON = false;\r\n    currentMessage = 51; \/\/Tell p5.js heater is on \/ AC is off\r\n    sendMessage(currentMessage);\r\n  } else if (goalTemp &lt; T &amp;&amp; heaterON) {\r\n    digitalWrite(hotPin, LOW);\r\n    digitalWrite(coldPin, HIGH);\r\n    heaterON = false;\r\n    acON = true;\r\n    currentMessage = 50; \/\/Tell p5.js heater is off \/ AC is on\r\n    sendMessage(currentMessage);\r\n  }\r\n\r\n}\r\n\r\n\r\nvoid doPlatePresenceCheck() {\r\n\r\n  int standingThreshold = 600;\r\n  int standingTimeThreshold = 2000; \/\/ [ms]\r\n  static bool timingStand = false;\r\n  static bool someoneOnPressurePlate = false;\r\n  static unsigned long standingTime = 0;\r\n\r\n\r\n  int plateReading = analogRead(pressurePlate);\r\n\r\n  if (plateReading &gt; standingThreshold) {\r\n    if (!timingStand) {\r\n      timingStand = true;\r\n      standingTime = millis();\r\n    }\r\n  } else if (plateReading &lt; standingThreshold &amp;&amp; someoneOnPressurePlate) {\r\n    timingStand = false;\r\n    someoneOnPressurePlate = false;\r\n    digitalWrite(presenceIndicator, LOW);\r\n    currentMessage = 40;\r\n    sendMessage(currentMessage);\r\n  }\r\n\r\n  if (timingStand &amp;&amp; millis() - standingTime &gt; standingTimeThreshold &amp;&amp; !someoneOnPressurePlate) {\r\n    timingStand = false;\r\n    someoneOnPressurePlate = true;\r\n    digitalWrite(presenceIndicator, HIGH);\r\n    currentMessage = 41;\r\n    sendMessage(currentMessage);\r\n  }\r\n\r\n}\r\n\r\n\r\nvoid handleLockButton() {\r\n  if (!DEBOUNCE_LOCK) {\r\n    DEBOUNCE_LOCK = true;\r\n    lockState = !lockState;\r\n    receivedMessage = false;\r\n  }\r\n}\r\n\r\nvoid toggleLockState(int lockState) {\r\n  int numOfBlinks = 5;\r\n\r\n  if (lockState) {\r\n    \/\/Unlock door\r\n    lockServo.write(179);\r\n    delay(15);\r\n\r\n    \/\/Turn light on\r\n    digitalWrite(lockLight, LOW);\r\n    for (int i = 0; i &lt; numOfBlinks; i++) {\r\n      digitalWrite(unlockLight, HIGH);\r\n      delay(100);\r\n      digitalWrite(unlockLight, LOW);\r\n      delay(50);\r\n    }\r\n    digitalWrite(unlockLight, HIGH);\r\n\r\n    \/\/Start timing unlock\r\n    prevUnlockTime = millis();\r\n\r\n    \/\/Indicate locking state to p5\r\n    currentMessage = 31;\r\n    sendMessage(currentMessage);\r\n\r\n\r\n  } else {\r\n    \/\/Lock door\r\n    lockServo.write(0);\r\n    delay(15);\r\n\r\n    \/\/Turn lock light on and unlock light off\r\n    digitalWrite(unlockLight, LOW);\r\n    for (int i = 0; i &lt; numOfBlinks; i++) {\r\n      digitalWrite(lockLight, HIGH);\r\n      delay(100);\r\n      digitalWrite(lockLight, LOW);\r\n      delay(50);\r\n    }\r\n    digitalWrite(lockLight, HIGH);\r\n\r\n    \/\/Indicate locking state to p5\r\n    currentMessage = 30;\r\n    sendMessage(currentMessage);\r\n\r\n\r\n  }\r\n}\r\n\r\n\r\nvoid button2Pressed() {\r\n  if (!DEBOUNCE2) {\r\n    DEBOUNCE2 = true;\r\n    lamp2state = !lamp2state;\r\n    digitalWrite(lamp2pin, lamp2state);\r\n  }\r\n}\r\n\r\nvoid button1Pressed() {\r\n  if (!DEBOUNCE1) {\r\n    DEBOUNCE1 = true;\r\n    lamp1state = !lamp1state;\r\n    digitalWrite(lamp1pin, lamp1state);\r\n  }\r\n}\r\n\r\nvoid parseInput(int inputData) {\r\n  int y = inputData;\r\n\r\n  if (y == 10 &amp;&amp; prevInMessage != 10) { \/\/1\r\n    lamp1state = 0;\r\n    digitalWrite(lamp1pin, LOW);\r\n  } else if (y == 11 &amp;&amp; prevInMessage != 11) { \/\/1\r\n    lamp1state = 1;\r\n    digitalWrite(lamp1pin, HIGH);\r\n  } if (y == 20 &amp;&amp; prevInMessage != 20) { \/\/1\r\n    lamp2state = 0;\r\n    digitalWrite(lamp2pin, LOW);\r\n  } else if (y == 21 &amp;&amp; prevInMessage != 21) { \/\/1\r\n    lamp2state = 1;\r\n    digitalWrite(lamp2pin, HIGH);\r\n  } else if (y == 30 &amp;&amp; prevInMessage != 30) { \/\/2\r\n    lockState = 0;\r\n    toggleLockState(lockState);\r\n    receivedMessage = true;\r\n  } else if (y == 31 &amp;&amp; prevInMessage != 31) { \/\/3\r\n    lockState = 1;\r\n    toggleLockState(lockState);\r\n    receivedMessage = true;\r\n  }\r\n\r\n}\r\n\r\n\r\n\r\n\r\nvoid sendMessage(int message) {\r\n  for (int i = 0; i &lt; 10; i++) {\r\n    Serial.println(message);\r\n    delay(40);\r\n  }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sims&#8230;but its you &nbsp; Description: I decided to take my previous visual crit further for this final crit by adding more components from a typical house into the control scheme\/visualization method. The idea is to create a little virtual world where the user can visualize and interact with things going on in their home related &hellip; <a href=\"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/?p=2564\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Final Crit &#8211; James Kyle&#8221;<\/span><\/a><\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/posts\/2564"}],"collection":[{"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2564"}],"version-history":[{"count":6,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/posts\/2564\/revisions"}],"predecessor-version":[{"id":2592,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=\/wp\/v2\/posts\/2564\/revisions\/2592"}],"wp:attachment":[{"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/courses.ideate.cmu.edu\/48-339\/s2022\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}